上篇文章中说到的 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
的异步解决方案。