你离异步只有一个语法糖的距离。

syntax sugar

使用 Promise 编写 JavaScript 异步代码已经司空见惯。

但是 Promise 写多了还是觉得有些繁琐。

对此,一个新的语法糖提案被提出。

那就是 async 和 await 。

async

async 用于标识一个函数为异步函数。被标识的函数返回一个 Promise 。

也就是 async 其实只是一个语法糖。

内部的实现还是 Promise 。

相当于返回 Promise 的同步函数。

await

await 用于等待一个异步函数。

也就是用于取出 Promise 的值。

举一个简单的例子

1
2
3
4
async function sample() {
var data = await Promise.resolve(1)
console.log(data)
}

只有标识了 async 的函数才能在函数体中使用 await 。不然会报错。

await 后面的代码会在 Promise resolve 后才执行。但是并不会造成程序阻塞。

因为底层还是用 Promise 实现的。

new era

用 async 和 await 改写Promise 异步编程的例子

Promise 的例子代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
function getData(callback) {
setTimeout(function (){
var data = 0;
console.log("数据拉取成功");
callback(data);
},1000);
console.log("拉取中……")
}

function handleData(data) {
return new Promise(function(resolve){
console.log("处理中……");
setTimeout(function(){
data += 1;
console.log("处理数据完成");
resolve(data);
},2000);
});
}

function sendData(data) {
return new Promise(function(resolve){
console.log("发送中……");
setTimeout(function(){
console.log("数据发送成功");
resolve(data);
},3000);
});
}

function showSucess(data){
console.log("恭喜充值成功游戏时间 +" + data + "s!");
}

var async = new Promise(function(resolve){
getData(resolve)
});

async.then(handleData).then(sendData).then(showSucess);

用 async 和 await 改写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
function TakeSeveralSeconds() {
let ms = Math.random() * 1000 + 1000
return new Promise(resolve => setTimeout(() => {
console.log("耗时 " + ms + " 毫秒")
resolve(ms)
}, ms))
}

async function getData() {
console.log("拉取中……")
await TakeSeveralSeconds()
var data = 0
console.log("数据拉取成功")
return data
}

async function handleData(data) {
console.log("处理中……")
await TakeSeveralSeconds()
data += 1
console.log("处理数据完成")
return data
}

async function sendData(data) {
console.log("发送中……")
await TakeSeveralSeconds()
console.log("数据发送成功")
return data
}

function showSucess(data) {
console.log("恭喜充值成功游戏时间 +" + data + "s!")
}

async function main() {
let data = await getData()
let handledData = await handleData(data)
let sendedData = await sendData(handledData)
showSucess(sendedData)
}

运行 main() 得到以下输出

1
2
3
4
5
6
7
8
9
10
11
12
main()
拉取中……
Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
耗时 1438.6931921290636 毫秒
数据拉取成功
处理中……
耗时 1511.1830960750424 毫秒
处理数据完成
发送中……
耗时 1644.7195288709415 毫秒
数据发送成功
恭喜充值成功游戏时间 +1s!

polyfill

从 Chrome 55 开始,Chrome 默认启用 async 和 await 。其他情况可以使用 babel 转译。

by the way

async 和 await 的本质是编译器做了 CPS 变换,新加的两个 Monad 的语法糖。有什么难的(逃