async/await剖析
2020-06-20 21:21
302 查看
async/await剖析
JavaScript是单线程的,为了避免同步阻塞可能会带来的一些负面影响,引入了异步非阻塞机制,而对于异步执行的解决方案从最早的回调函数,到
ES6的
Promise对象以及
Generator函数,每次都有所改进,但是却又美中不足,他们都有额外的复杂性,都需要理解抽象的底层运行机制,直到在
ES7中引入了
async/await,他可以简化使用多个
Promise时的同步行为,在编程的时候甚至都不需要关心这个操作是否为异步操作。
分析
首先使用
async/await执行一组异步操作,并不需要回调嵌套也不需要写多个
then方法,在使用上甚至觉得这本身就是一个同步操作,当然在正式使用上应该将
await语句放置于
try...catch代码块中,因为
await命令后面的
Promise对象,运行结果可能是
rejected。
function promise(){ return new Promise((resolve, reject) => { var rand = Math.random() * 2; setTimeout(() => resolve(rand), 1000); }); } async function asyncFunct(){ var r1 = await promise(); console.log(1, r1); var r2 = await promise(); console.log(2, r2); var r3 = await promise(); console.log(3, r3); } asyncFunct();
async/await实际上是
Generator函数的语法糖,如
Promises类似于结构化回调,
async/await在实现上结合了
Generator函数与
Promise函数,下面使用
Generator函数加
Thunk函数的形式实现一个与上边相同的例子,可以看到只是将
async替换成了
*放置在函数右端,并将
await替换成了
yield,所以说
async/await实际上是
Generator函数的语法糖,此处唯一不同的地方在于实现了一个流程的自动管理函数
run,而
async/await内置了执行器,关于这个例子的实现下边会详述。对比来看,
async和
await,比起
*和
yield,语义更清楚,
async表示函数里有异步操作,
await表示紧跟在后面的表达式需要等待结果。
function thunkFunct(index){ return function f(funct){ var rand = Math.random() * 2; setTimeout(() => funct(rand), 1000) } } function* generator(){ var r1 = yield thunkFunct(); console.log(1, r1); var r2 = yield thunkFunct(); console.log(2, r2); var r3 = yield thunkFunct(); console.log(3, r3); } function run(generator){ var g = generator(); var next = function(data){ var res = g.next(data); if(res.done) return ; // console.log(res.value); res.value(next); } next(); } run(generator);
实现
async函数内置了执行器,能够实现函数执行的自动流程管理,通过
Generator yield Thunk、
Generator yield Promise实现一个自动流程管理,只需要编写
Generator函数以及
Thunk函数或者
Promise对象并传入自执行函数,就可以实现类似于
async/await的效果。
Generator yield Thunk
自动流程管理
run函数,首先需要知道在调用
next()方法时,如果传入了参数,那么这个参数会传给上一条执行的
yield语句左边的变量,在这个函数中,第一次执行
next时并未传递参数,而且在第一个
yield上边也并不存在接收变量的语句,无需传递参数,接下来就是判断是否执行完这个生成器函数,在这里并没有执行完,那么将自定义的
next函数传入
res.value中,这里需要注意
res.value是一个函数,可以在下边的例子中将注释的那一行执行,然后就可以看到这个值是
f(funct){...},此时我们将自定义的
next函数传递后,就将
next的执行权限交予了
f这个函数,在这个函数执行完异步任务后,会执行回调函数,在这个回调函数中会触发生成器的下一个
next方法,并且这个
next方法是传递了参数的,上文提到传入参数后会将其传递给上一条执行的
yield语句左边的变量,那么在这一次执行中会将这个参数值传递给
r1,然后在继续执行
next,不断往复,直到生成器函数结束运行,这样就实现了流程的自动管理。
function thunkFunct(index){ return function f(funct){ var rand = Math.random() * 2; setTimeout(() => funct(rand), 1000) } } function* generator(){ var r1 = yield thunkFunct(); console.log(1, r1); var r2 = yield thunkFunct(); console.log(2, r2); var r3 = yield thunkFunct(); console.log(3, r3); } function run(generator){ var g = generator(); var next = function(data){ var res = g.next(data); if(res.done) return ; // console.log(res.value); res.value(next); } next(); } run(generator);
Generator yield Promise
相对于使用
Thunk函数来做流程自动管理,使用
Promise来实现相对更加简单,
Promise实例能够知道上一次回调什么时候执行,通过
then方法启动下一个
yield,不断继续执行,这样就实现了流程的自动管理。
function promise(){ return new Promise((resolve,reject) => { var rand = Math.random() * 2; setTimeout( () => resolve(rand), 1000); }) } function* generator(){ var r1 = yield promise(); console.log(1, r1); var r2 = yield promise(); console.log(2, r2); var r3 = yield promise(); console.log(3, r3); } function run(generator){ var g = generator(); var next = function(data){ var res = g.next(data); if(res.done) return ; res.value.then(data => next(data)); } next(); } run(generator);
// 比较完整的流程自动管理函数 function promise(){ return new Promise((resolve,reject) => { var rand = Math.random() * 2; setTimeout( () => resolve(rand), 1000); }) } function* generator(){ var r1 = yield promise(); console.log(1, r1); var r2 = yield promise(); console.log(2, r2); var r3 = yield promise(); console.log(3, r3); } function run(generator){ return new Promise((resolve, reject) => { var g = generator(); var next = function(data){ var res = null; try{ res = g.next(data); }catch(e){ return reject(e); } if(!res) return reject(null); if(res.done) return resolve(res.value); Promise.resolve(res.value).then(data => { next(data); },(e) => { throw new Error(e); }); } next(); }) } run(generator).then( () => { console.log("Finish"); });
每日一题
https://github.com/WindrunnerMax/EveryDay
参考
https://segmentfault.com/a/1190000007535316 http://www.ruanyifeng.com/blog/2015/05/co.html http://www.ruanyifeng.com/blog/2015/05/async.html
相关文章推荐
- 探索c#之Async、Await剖析
- 聊聊多线程那一些事儿 之 五 async.await深度剖析
- C# 探索c#之Async、Await剖析
- [C#]剖析异步编程语法糖: async和await
- 探索c#之Async、Await剖析
- c#之Async、Await剖析
- 聊聊多线程那一些事儿 之 五 async.await深度剖析
- [C#]剖析异步编程语法糖: async和await
- async and await 的入门基础操作
- .Net 4.5 Async & Await 用法
- Visual Studio Async CTP的实现原理浅析 - 如何不使用async和await关键字来实现Async
- JavaScript里的await/async的作用和用法
- async & await 的前世今生
- Async 和 Await的性能(.NET4.5新异步编程模型)
- 初识async与await
- .NET 基于任务的异步模式(Task-based Asynchronous Pattern,TAP) async await
- 说说C#的async和await
- [Node] Catch error for async await
- The Task: Events, Asynchronous Calls, Async and Await
- async & await 的前世今生