Hey async,await me

背景

笔者在前面的文章介绍过如何使用generator来解决callback hell,尽管现在多数浏览器特别是移动端浏览器还不支持该ES2015新特性,但你可以通过Babel等转换工具转化成ES5兼容的等效代码,从而在生产环境使用。

不过使用generator来解决callback hell似乎有点不务正业,毕竟generator是生成器,属于Iterator的一种,设计之初是用来生成一种特殊的迭代器的。

另外还有两点也可以算是generator解决callback hell问题的缺陷:

  1. generator需要从generator function执行得到,而generator function执行之后只会返回一个generator,不管里面是怎样的代码,与我们通常对函数的认知存在差异

  2. 如果想执行generator function的函数体,需要不断调用返回的generator的next方法,这样就决定了必须依赖cobluebird.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的解决方式

1

2

3

4

5

6

7

8

9

10

11

12

(async () => {

    try {

        // 获取用户名

        const name = await $.ajax('get_my_name');

        // 根据用户名获取个人信息

        const info = await $.ajax(`get_my_info_by_name'?name=${name}`);

        // 打印个人信息

        console.log(