异步编程 | async/await
ES8提出的async/await关键词旨在解决利用异步结构组织代码的问题
异步函数基础
async
async关键字用于声明异步函数
- async关键字可以在函数声明、函数表达式、箭头函数、函数方法上使用
1 | // 函数声明 |
使用async关键字可以让函数具有异步特征,但总体上函数仍然是同步求值的,在参数或者闭包方面,异步函数仍然具有普通JavaScript函数的正常行为
异步函数始终返回Promise对象
- 如果异步函数内部有显式的return语句并且返回值(没有return 值就是undefined),这个值会被Promise.resolve()包装成一个Promsie对象
- 如果异步函数直接return一个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
27async function foo() {
console.log(1);
return 3;
}
// 给返回的promise添加一个then方法的解决处理程序
foo().then(console.log);
console.log(2);
// 1 这个是foo()调用得到的
// 2
// 3 这个是then()处理的结果
async function foo() {
console.log(1);
return Promise.resolve(3);
}
foo().then(console.log);
console.log(2);
// 1 这个是foo()调用得到的
// 2
// 3 这个是then()处理的结果异步函数的返回值期待一个实现
thenable
接口的对象,但常规值也可以- 如果返回的是实现
thenable
接口的对象,则这个对象可以由提供给then()
的处理程序“解包” - 如果不是,则返回子和就被当作已解决的Promise
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23// 返回一个原始值
async function foo() {
return 'foo';
}
foo().then(value => console.log(value)); // 'foo'
// 返回一个没有实现thenable接口的对象
async function bar() {
return ['bar']
}
bar().then(value => console.log(value)); // ['bar']
// 返回一个实现thenabke接口的对象
async function baz() {
const thenable = {
then(callback) {
callback('baz');
}
};
return thenable;
}
baz().then(value => console.log(value)); // 'baz'- 如果返回的是实现
在异步函数中抛出错误会返回拒绝的Promise
1 | async function foo() { |
- 拒绝Promise的错误不会被异步函数捕获
1 | async function foo() { |
await
await关键词可以暂停异步函数代码的执行,等待Promise的解决
await
可以单独使用也可以在表达式中使用await
关键字会暂停执行异步函数后面的代码,让出JavaScript
运行时的执行线程,这个行为与生成器函数中的yield
关键字是一样的,await
关键字同样是尝试“解包”对象的值,然后将这个值传给表达式,再异步恢复异步函数的执行await
关键字期待(但实际上并不要求)一个实现thenable 接口的对象,但常规的值也可以,如果是实现thenable 接口的对象,则这个对象可以由await 来“解包”,如果不是,则这个值就被当作已经解决的Promise
1 | // 等待一个原始值 |
await
会抛出错误的同步操作,会返回拒绝的Promise
1 | async function foo() { |
- 对拒绝的
Promise
使用await
则会释放(unwrap
)错误值(将拒绝Promise返回)
1 | async function foo() { |
await关键字有一定限制
- await关键字必须在异步函数中使用,不能在顶级上下文如