View on GitHub

Yinjie - GitHub.io

Welcome to the Yinjie's notes

上篇文章中说到的 promise 在进行异步代码同步化处理的进程上迈出了第一步,但离完美还差挺多。 数据返回端看似是可以直接 return 返回结果数据了,但是数据接收端还是没什么本质改变。

在 ES7 中,又给出了一种新的特性:await/async。从字面就可以看出,这是专门解决 JS 异步过程的一种方式。

基础介绍

还是看前面的那个例子:

function getUserinfo(uid) {
    return new Promise(function (resolve, reject) {
        resolve({
            name: '张三',
            age: '21',
        });
        // reject('something error');
    });
}

方法返回的是一个 promise 对象时,在数据接收端,用 await/async 就可以做到“真正”的同步接收,注意两个关键字的位置。

async function eg() {
    let userinfo;
    try {
        userinfo = await getUserinfo('u123321');
        console.log(userinfo);
    } catch (err) {
        console.log(err);
        userinfo = null;
    }
    return userinfo;
}
eg();

这个时候,你就可以发现,userinfo 不再是一个 promise,而是 {name: '张三', age: 21}。 是不是非常给力~ 个人感觉是这个除了 ‘class’ 外又一非常爽的语法特性。 但是使用时需要注意以下几点:

使用注意

数据接收代码必须在一个 function

从上面的例子就可以注意到,是又写了一个 async 方法 eg,在里面去 await 调用 getUserinfo,才会有想要的结果。

这种形式是必须的,有时也是一个小小的不便。是因为其编译原理造成的,有兴趣可以自己去查看。

错误捕获

var userinfo = await getUserinfo('u123321'); 获取的是 promise 对象 resolve 的结果,那么出错时的 reject 怎么获取?

经典的 try-catch 语法就可以捕获到相关错误了。如果不写 try-catch,在最新的 nodejs 版本里会出运行出错,所以还是乖乖的写上吧, runtime 错误容错处理是一个程序员的基本素质。

传递性

如果我在上面的例子上再加一个方法调用 eg,如下:

function eg2() {
    const userinfo = eg();
    console.log(userinfo);
}

eg2();

想想看打印出的是什么,按常理:eg 方法已经‘同步’获得了 userinfo,再 return 出去,eg2 接收到的应该也是 {name: '张三', age: 21},但是实际上却又回到了之前的 promise 对象。

这就是 await/async 的传递性:一但从上使用 await/async 同步获取了数据,之后其它方法再获取 async 方法的数据,自己也必须是一个 async 方法。正确的方法如下:

// 正确的方法
async function eg2() {
    const userinfo = await eg();
    console.log(userinfo);
}

eg2();

支持情况

浏览器端肯定是不支持的了,如果想使用此语法时,需要通过 babel-plugin-syntax-async-functions 编译成 es5 语法。

nodejs 7+ 已经可以原生支持了,但是默认没有打开此特性,需要我们手动加上 --harmony 参数执行。


下一篇简要说一下 generator 的异步解决方案。