我们在之前讲解async时提到了由Promise转变至async所经历的一系列过程。
由于Promise只能通过catch捕获错误,而在内部.then链中嵌套的一系列Promise调用所产生的err是无法被外层catch所捕获的,而其后添加catch则又破坏了代码的格式和一致性。
同时,Promise中的catch函数中的异常堆栈不够完整,依旧难以追寻真正发生错误的位置(因为内部调用大都是匿名函数。而不用匿名函数则又丧失了箭头函数的简洁,让开发者很苦恼)。
所以,Async语法应运而生。他弥补了上述Promise调用所出现的不足之处,而其具体实现则是通过Generator和Promise协同的语法糖。下面我们一起看看如何通过Generator和Promise实现一个Async-Await吧~
Generator
Generator是一个函数,通过yield关键字控制其执行- 执行该函数时到第一个
yield时停止执行,直到调用其返回值的.next()才会执行yield后面的部分,返回一个带有value和done属性的对象,其机制类似于return,到此为止,返回结果。 - 我们可以在调用
next()时传递一个参数,在上次yield前接收到这个参数 - 同时,
Generator内部仍可以嵌套Generator函数,具体实现就是yield*,在此不再赘述。
在此只对其做一个粗浅的概述,若各位有兴趣可以看相关的博客: 《ES6中的Generator》
Promise
- 每次返回更新自己的状态(
fullfied||rejected),返回值仍为一个Promise
实现
实现之前我们需要明确:
generator生成器返回值是一个对象({value: XXX, done: true})async-await返回的是一个Promise。
所以我们若想实现功能,必须将Promise塞进field之中去
1 | function run (gen) { |
由代码可知我们通过generator——main函数以近似同步的方式执行异步代码。但这同时也需要一个外部函数帮助我们执行这个main。
而其对应的async/await函数实现上方代码如下
1 | function getRandom () { |
大体上看我们只需要将*改为async,将yield改成await,且免去了外部调用的main函数。
事实上Generator作为一个生成器,用以完成异步代码的近同步化确实有些不务正业。不过的确有相关的库(co)用以将Promise和Generator实现其功能,有兴趣的boy可以查询相关文档。
总结
Generator生成器返回的对象是一个类似于{value: XXX, done: true}结构的Object。而Async则始终返回一个Promise,使用await或.then()获取返回值。
相较于Generator + co,Async生来就是为了处理异步编程,对此更加专业,所以还是让Generator干他自己的老本行去8~