JavaScript ES7 中的 async 和 await

ES7 中会新增 async / await 用于处理异步请求,使开发者能像处理同步请求一样处理异步请求。发起一个异步请求之后,获取到了请求结果,再进行下一步操作,使整个流程看起来就是同步流程;

Prepare

由于当前浏览器并不直接支持最新的 es7 语法,所以需要使用转换器将 es7 语法下的 javascript 转换成 es5 语法的代码块;可以使用 babel 转换器进行转换,需要安装如下几个插件:

1
2
3
4
5
"dependencies": {
"babel-core": "^6.24.1",
"babel-loader": "^7.0.0",
"babel-preset-stage-3": "^6.24.1"
},

异步请求

假如有一个函数,需要在执行过程中暂停指定的一段时间,然后再向下执行;

1
2
3
4
5
6
7
8
9
10
11
var sleep = function(time) {
return new Promise((resolve, reject)=> {
setTimeout(()=> {
if(time >= 1000){
resolve("function sleep is invoked after " + time + " ms");
}else{
reject("function sleep is invoked after " + time + "ms, sleepTime should be longer");
}
}, time);
});
};

CommonInvoke 普通调用

1
2
3
4
5
6
7
var commonInvoke = ()=> {
sleep(1200).then((info)=>{
console.log('commonInvoke');
console.log(info);
});
};
commonInvoke();

使用 async & await 函数

1
2
3
4
5
6
7
8
9
10
11
12
var asyncInvoke = async ()=> {
console.log('async function begin');
var result = await sleep(1100);
console.log(result);
console.log('after await => async end with success');
};
asyncInvoke();
// 输出结果
async function begin // 等待1s后再输出下面的内容
function sleep is invoked after 1100 ms
after await => async end with success

在使用 async & await 之后,可以在等 sleep 函数执行完成返回异步函数的结果值之后,再继续向下执行。await 等待的虽然是 promise 对象,但不必写 .then(..),可以直接得到返回值。上面的输出结果中第二行输出即是 sleeppromise 的返回值;

async & await 使用规则:

  • async 表示这是一个async函数,await只能用在这个函数里面。
  • await 表示此行代码需要等待sleep返回的promise执行完成后再继续向下执行。
  • await 后面跟着的应该是一个promise对象(当然其他值也没关系,只是会立即执行,不过那样没有意义)

错误捕获

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var asyncInvokeRejected = async ()=> {
try {
console.log('async function begin');
var result = await sleep(500);
console.log(result);
console.log('after await => async end with success');
} catch(err) {
console.log(err);
console.log('after await => async end with error');
}
};
asyncInvokeRejected();
// 输出结果
async function begin
function sleep is invoked after 500ms, sleepTime should be longer
after await => async end with error

由于给 sleep 的暂停时间小于1000,所以 sleep 函数中 promise 对象调用了 reject 函数表示函数执行不成功,普通调用方法下捕获异常是 p.then(…).catch(…),但是在使用 async / await 的时候,可以直接使用 try {…} catch (err) {} 来捕获异常;

循环执行

await 看起来就像是同步代码,所以可以理所当然的写在for循环里,不必担心以往需要 闭包 才能解决的问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function getTime() {
return new Date().getTime();
}
var asyncInvokeLoop = async ()=> {
for(var i = 0; i < 3; i++) {
console.log('invoked ' + i + " times");
await sleep(1000);
console.log(getTime());
}
};
asyncInvokeLoop();
// 输出结果
// invoked 0 times
// 1493709175574
// invoked 1 times
// 1493709176580
// invoked 2 times
// 1493709177582

需要注意的是 await 必需是要在 async 的上下文中,如下便是一个错误的调用:

1
2
3
4
5
var arr = [1, 2, 3];
arr.forEach(function (v) {
console.log(`当前是第${v}次等待..`);
await sleep(1000); // 错误!! await只能在async函数中运行
});

Link