前言
随着 Node 7 的发布,越来越多的人开始研究据说是异步编程终级解决方案的 async/await,在我们的很多项目中都已经开始使用async函数,下面就来一起理解下Javascript处理异步的async函数。
初识async/await
Async/await 是Javascript编写异步程序的新方法。以往的异步方法无外乎回调函数和Promise。但是Async/await建立于Promise之上,async 函数算是一个语法糖,使异步函数、回调函数在语法上看上去更像同步函数,很多人认为它是异步操作的终极解决方案。
async/await语法
async
async函数返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。
1 | async function test () { |
在没有 await 的情况下执行 async 函数,它会立即执行,返回一个 Promise 对象,并且,绝不会阻塞后面的语句。这和普通返回 Promise 对象的函数一样。所以这个await函数就至关重要了。
await
正常情况下,await命令后面是一个 Promise 对象。如果不是,会被转成一个立即resolve的 Promise 对象。
1 | async function testAwait() { |
只要一个await语句后面的 Promise 变为reject,那么整个async函数都会中断执行.
1 | async function testAwait() { |
所以当一个 async 函数中有多个 await命令时,如果不想因为一个出错而导致其与的都无法执行,应将await放在try…catch语句中执行1
2
3
4
5
6
7
8
9
10
11async function testAwait {
try {
await Promise.reject('出错了');
} catch(e) {
}
return await Promise.resolve('hello world');
}
testAwait()
.then(v => console.log(v))
// hello world
另一种方法是await后面的 Promise 对象再跟一个catch方法,处理前面可能出现的错误。1
2
3
4
5
6
7
8
9
10async function testAwait() {
await Promise.reject('出错了')
.catch(e => console.log(e));
return await Promise.resolve('hello world');
}
testAwait()
.then(v => console.log(v))
// 出错了
// hello world
并发执行 await 命令
当一个 async 函数中有多个await时,这些 await是继发执行的,只有当前一个await后面的方法执行完毕后,才会执行下一个。
如果我们前后的方法由依赖关系,继发执行是没有问题的,但是如果并没有任何关系的话,这样就会很耗时,所以需要让这些await命令同时执行,也就是并发执行
1 | // 方法 1 使用Promise.all |
错误处理
如果await后面的异步操作出错,那么等同于async函数返回的 Promise 对象被reject。
防止出错的方法,也是将其放在try…catch代码块之中。1
2
3
4
5
6
7
8
9async function errtest() {
try {
await new Promise(function (resolve, reject) {
throw new Error('出错了');
});
} catch(e) {
}
return await('hello world');
}
如果有多个await命令,可以统一放在try…catch结构中。1
2
3
4
5
6
7
8
9
10
11
12async function errtest() {
try {
const val1 = await firstStep();
const val2 = await secondStep(val1);
const val3 = await thirdStep(val1, val2);
console.log('Final: ', val3);
}
catch (err) {
console.error(err);
}
}
注意点
- await 命令后面的 Promise 对象,运行结果可能是 rejected,所以最好把 await 命令放在 try…catch 代码块中。
- 使用async关键字声明异步函数。
- await 命令只能用在 async 函数之中,如果用在普通函数,就会报错。
- async用来申明里面包裹的内容可以进行同步的方式执行,await则是进行执行顺序控制,每次执行一个await,程序都会暂停等待await返回值,然后再执行之后的await。
- 多个await命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。
async/await 的优势
then 链
单一的 Promise 链并不能发现 async/await 的优势,但是,如果需要处理由多个 Promise 组成的 then 链的时候,优势就能体现出来了(很有意思,Promise 通过 then 链来解决多层回调的问题,现在又用 async/await 来进一步优化它)。
中间值
一个经常出现的场景是,我们先调起promise1,然后根据返回值,调用promise2,之后再根据这两个Promises得值,调取promise3。
对比一下Promise和async/await的实现方式,就可以发现 async/await代码非常简单,结构清晰1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19// Promise
const makeRequest = () => {
return promise1()
.then(value1 => {
// do something
return promise2(value1)
.then(value2 => {
// do something
return promise3(value1, value2)
})
})
}
// async/await
const makeRequest = async () => {
const value1 = await promise1()
const value2 = await promise2(value1)
return promise3(value1, value2)
}
还有很多的优点,就看大家实际项目中去挖掘了。
thank you