早期的网页都是静态页面,也不存在前后端分离,随着互联网的兴起了网站应用的增加,网站需要更多的和服务器交互,这时候为了实现异步处理,出现了ajax,我们采用setTimeout
来模拟服务端请求。
1 2 3 4 5 6 7 8 9
| function ajax() { setTimeout(() = >{ console.log('之前执行'); }, 2000) }
ajax(); console.log('之后执行');
|
运行代码结果:
这并不是我想要的结果,因为代码是自上而下执行,遇到异步请求代码片段延迟执行,而异步代码片段外继续执行,这时候我们可以通过函数做为参数改进代码。
1 2 3 4 5 6 7 8 9 10 11
| function ajax(fn) { setTimeout(() = >{ console.log('之前执行'); fn() }, 2000) }
ajax(() = >{ console.log('之后执行'); });
|
运行代码结果:
这样虽然暂时是我们想要的效果,但是当应用庞大,后一个请求依赖前一个请求执行的结果时,就容易陷入回调地狱模式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| function ajax(fn) { setTimeout(() = >{ console.log('之前执行'); fn() }, 2000) }
ajax(() = >{ console.log('之后执行1'); ajax(() = >{ console.log('之后执行2'); ajax(() = >{ console.log('之后执行3'); }); }); });
|
运行代码结果:
1 2 3 4 5 6 7
| 之前执行 之后执行1 之前执行 之后执行2 之前执行 之后执行3
|
上面这样就陷入了回调地狱,一旦项目过大,就造成难以调试和维护的问题,为了解决回调地狱的问题,Promise
出现了。
1 2 3 4 5 6 7 8 9 10 11 12
| function delay(text) { return new Promise((resolve, reject) = >{ setTimeout(() = >{ resolve(text); }, 2000) }) }
delay('hello one').then((msg) = >{ console.log(msg); })
|
运行代码结果:
Promise
就相当于一个承诺,内部的函数的参数有两个,一个是成功解决resolve
,另一个是拒绝reject
,显著特征就是then
、catch
的回调,如上面案例所示,如果想要嵌套执行,就需要多次链式then
回调。
1 2 3 4 5 6 7 8 9 10 11 12
| delay('one').then((msg) = >{ console.log(msg); return delay('two'); }).then((msg) = >{ console.log(msg); return delay('three'); }).then((msg) = >{ console.log(msg); }). catch(error = >{ })
|
代码执行结果:
这样的代码在很大程度上解决了回调地狱的问题,但是不断地链式回调的代码看起来并不是很优雅,因此出现了async await
,它让异步代码看起来和同步代码一样优雅。
1 2 3 4 5 6 7 8 9 10
| async function start() { const txt1 = await delay('one'); console.log(txt1); const txt2 = await delay('two'); console.log(txt2); const txt3 = await delay('three'); console.log(txt3); }
start();
|
代码执行结果: