async与await语法
# 解决了什么问题
ES7的async
/await
语法在2016年就已经提出来了,在async
/await
之前,我们有三种方式写异步代码
嵌套回调
以
Promise
为主的链式回调使用 Generators
但是,这三种写起来都不够优雅,ES7做了优化改进,async/await
应运而生,async/await
相比较Promise
对象then
函数的嵌套,与 Generator
执行的繁琐(需要借助co才能自动执行,否则得手动调用next()
), Async/Await
可以让你轻松写出同步风格的代码同时又拥有异步机制,更加简洁,逻辑更加清晰。
# async/await特点
async/await
更加语义化,async
是“异步”的简写,async function
用于申明一个function
是异步的;await
,可以认为是async wait
的简写, 用于等待一个异步方法执行完成;async/await
是一个用同步思维解决异步问题的方案(等结果出来之后,代码才会继续往下执行)可以通过多层
async function
的同步写法代替传统的callback
嵌套
# async function语法
自动将常规函数转换成
Promise
,返回值也是一个Promise
对象只有
async
函数内部的异步操作执行完,才会执行then
方法指定的回调函数异步函数内部可以使用
await
async function name([param[, param[, ... param]]]) { statements }
name: 函数名称。
param: 要传递给函数的参数的名称
statements: 函数体语句。
返回值: 返回的Promise对象会以async function的返回值进行解析,或者以该函数抛出的异常进行回绝。
2
3
4
5
# await语法
await
放置在Promise
调用之前,await
强制后面点代码等待,直到Promise
对象resolve
,得到resolve
的值作为await
表达式的运算结果await
只能在async
函数内部使用,用在普通函数里就会报错
[return_value] = await expression;
expression: 一个 Promise 对象或者任何要等待的值。
返回值:返回 Promise 对象的处理结果。如果等待的不是 Promise 对象,则返回该值本身。
2
3
4
5
# 错误处理
在async
函数里,无论是Promise reject
的数据还是逻辑报错,都会被默默吞掉,所以最好把await
放入try{}catch{
}中,catch
能够捕捉到Promise
对象rejected
的数据或者抛出的异常
function timeout(ms) {
return new Promise((resolve, reject) => {
setTimeout(() => {reject('error')}, ms); //reject模拟出错,返回error
});
}
async function asyncPrint(ms) {
try {
console.log('start');
await timeout(ms); //这里返回了错误
console.log('end'); //所以这句代码不会被执行了
} catch(err) {
console.log(err); //这里捕捉到错误error
}
}
asyncPrint(1000);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
如果不用try/catch
的话,也可以像下面这样处理错误(因为async
函数执行后返回一个promise
)
function timeout(ms) {
return new Promise((resolve, reject) => {
setTimeout(() => {reject('error')}, ms); //reject模拟出错,返回error
});
}
async function asyncPrint(ms) {
console.log('start');
await timeout(ms)
console.log('end'); //这句代码不会被执行了
}
asyncPrint(1000).catch(err => {
console.log(err); // 从这里捕捉到错误
});
2
3
4
5
6
7
8
9
10
11
12
13
14
如果你不想让错误中断后面代码的执行,可以提前截留住错误,像下面
function timeout(ms) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('error')
}, ms); //reject模拟出错,返回error
});
}
async function asyncPrint(ms) {
console.log('start');
await timeout(ms).catch(err => { // 注意要用catch
console.log(err)
})
console.log('end'); //这句代码会被执行
}
asyncPrint(1000);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 使用场景
多个await
命令的异步操作,如果不存在依赖关系(后面的await
不依赖前一个await返回的结果),用Promise.all()
让它们同时触发
function test1 () {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 1000)
})
}
function test2 () {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2)
}, 2000)
})
}
async function exc1 () {
console.log('exc1 start:',Date.now())
let res1 = await test1();
let res2 = await test2(); // 不依赖 res1 的值
console.log('exc1 end:', Date.now())
}
async function exc2 () {
console.log('exc2 start:',Date.now())
let [res1, res2] = await Promise.all([test1(), test2()])
console.log('exc2 end:', Date.now())
}
exc1();
exc2();
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
exc1
的两个并列await
的写法,比较耗时,只有test1
执行完了才会执行test2
,你可以在浏览器的Console
里尝试一下,会发现exc2
的用Promise.all
执行更快一些
- 02
- Node与GLIBC_2.27不兼容解决方案08-19
- 03
- Git清空本地文件跟踪缓存08-13