背景
笔者在前面的文章介绍过如何使用generator来解决callback hell,尽管现在多数浏览器特别是移动端浏览器还不支持该ES2015新特性,但你可以通过Babel等转换工具转化成ES5兼容的等效代码,从而在生产环境使用。
不过使用generator来解决callback hell似乎有点不务正业,毕竟generator是生成器,属于Iterator的一种,设计之初是用来生成一种特殊的迭代器的。
另外还有两点也可以算是generator解决callback hell问题的缺陷:
- generator需要从generator function执行得到,而generator function执行之后只会返回一个generator,不管里面是怎样的代码,与我们通常对函数的认知存在差异
- 如果想执行generator function的函数体,需要不断调用返回的generator的next方法,这样就决定了必须依赖co或bluebird.coroutine等其他辅助代码或者手动执行next,来保证generator不断next下去
Tips:文章ES6 Generator介绍有介绍generator和generator function,以及它们之间的关系和区别。
众所周知,ES2015来的太晚了,而现在,TC39决定加快脚步,也许每年都会有新版本发布,明年可能会发布ES2016。ES2016终于给JS带来了async/await原生支持,而其他语言如C#、Python等更早就支持上了。
而async/await正是本文要重点介绍的用来解决callback hell问题的终极大杀器。 虽然离浏览器或nodejs支持ES2016还有很久很久,但依靠babel任然可以转换出当前环境就支持的代码。
本文的最后还将分享笔者在生产环境使用async/await的经验,对,就是生产环境。
async/await语法
函数声明
1 |
async function asyncFunc() {} |
函数表达式
1 |
const asyncFunc = async function() {} |
匿名函数
1 |
async function() {} |
箭头函数
1 |
async () => {} |
类方法
1 2 3 |
Class someClass { async asyncFunc() {} } |
没什么特别的,就在我们通常的写法前加上关键字async就行了,就像generator function仅仅比普通function多了一个*。
function前面加上async关键字,表示该function需要执行异步代码。 async function函数体内可以使用await关键字,且await关键字只能出现在async function函数体内,这一点和generator function跟yield的关系一样。
1 2 3 |
async function asyncFunc() { await anything; } |
await关键字可以跟在任意变量或者表达式之前,从字面很好理解该关键字有等待的意思,所以更有价值的用法是await后面跟一个异步过程,通常是Promise,
1 2 3 |
async function asyncFunc() { await somePromise; } |
如果用generator来解决callback hell,必须配合使用yield关键字和next方法,而理解清楚yield的作用和返回值以及next的参数作用就够消化两天了,await关键字不像yield关键字和next方法这么难以理解,它的意思就是等待,作用也是等待,而且一个关键字就够了。
Tips:前文介绍yield的时候还提到了yield*,其实ES2016草案里面也提到了await*,不过它不是标准的一部分,草案并不要求必须实现,而且草案并不建议使用,不过后文还是会提到await*的用法。
做正确的事
用generator来解决异步函数回调问题始终觉得有些别扭,现在就让它做回本职工作吧,回调问题就交由async/await来解决——做正确的事。
先来回顾一下generator配合co来解决异步回调问题的方法,首先yy一个场景,见注释
1 2 3 4 5 6 7 8 9 10 11 12 |
co(*() => { try { // 获取用户名 const name = yield $.ajax('get_my_name'); // 根据用户名获取个人信息 const info = yield $.ajax(`get_my_info_by_name'?name=${name}`); // 打印个人信息 console.log(info); } catch(err) { console.error(err); } }); |
再来看看async/await的解决方式