异步函数,即async / await
,是基于Promise
的应用,可以让我们以同步的方式写异步的代码。
如下代码,一个使用Promise
的简单例子,Promise
对象中的函数参数中,写了一个定时器setTimeout
。定时器的第三个参数为10
,表示定时器结束后,10
将作为参数,传递给定时器的回调函数resolve
。这就意味着,定时器结束后,这个Promise
对象会解决为数值10
。
const p = new Promise((resolve, reject) => setTimeout(resolve, 1000, 10));
但是,如果访问到这个数值10
,需要调用then()
方法:
p.then(x => console.log(x)); // 10
这非常不方便,虽然解决了回调地域问题,但是后续代码必须要放在then()
方法里面。
在 ES8 中,JavaScript 支持了async / await
关键字,可以用同步的方式,写异步代码。
async
关键字用来声明异步函数,可以在函数声明、函数表达式、箭头函数、方法前声明使用:
// 函数声明
async function fun1() {}
// 函数表达式
const fun2 = async function () {};
// 箭头函数
const fun3 = async () => {};
// 方法
const obj = {
async fun4() {},
};
使用async
关键字可以让函数具有异步的特征,但代码还是同步求值的:
async function fun() {
console.log(1);
}
fun();
console.log(2);
// 1
// 2
如上代码,fun
函数被声明成异步函数,但总体代码仍然是同步执行的,因为先打印出了1
,再打印2
。
另外,被async
声明的函数如果使用return
返回了值(若没有return
,则返回undefined
),那么返回的值会被Promise.resolve()
包装成一个Promise
对象。所以,异步函数始终会返回Promise
对象。
如下代码,调用fun
函数,fun
函数内部首先打印出1
,接着返回Promise
对象,然后打印出2
,最后打印出Promise
对象解决的值3
。
async function fun() {
console.log(1);
return 3;
}
fun().then(console.log);
console.log(2);
// 1
// 2
// 3
异步函数内部直接返回一个Promise
对象也能达到同样效果,如下代码等价于上面的代码:
async function fun() {
console.log(1);
return Promise.resolve(3);
}
fun().then(console.log);
console.log(2);
// 1
// 2
// 3
但是,若Promise
被拒绝,那么将不会被异步函数捕获:
async function fun() {
console.log(1);
Promise.reject(3);
}
fun().then(console.log);
console.log(2);
// 1
// 2
// 报错:Unhandled promise rejection
使用await
关键字可以暂停异步函数代码的执行,等待Promise
解决。
本文首个例子:
const p = new Promise((resolve, reject) => setTimeout(resolve, 1000, 10));
p.then(x => console.log(x)); // 10
可以使用async
和await
关键字改写为:
async function fun() {
const p = new Promise((resolve, reject) => setTimeout(resolve, 1000, 10));
console.log(await p);
}
fun(); // 10
await
关键字会暂停执行异步函数后面的代码,让出 JavaScript 运行时的执行线程。
但是,await
必须和async
一起使用,也就是说,await
只能写在被async
声明过的异步函数中。若await
写在同步函数中,将会报错:
function fun() {
let a = await 1; // SyntaxError: await is only valid in async function
console.log(a);
}
fun();
参考:
《JavaScript高级程序设计(第4版)》
欢迎在我的博客上访问:
https://lzxjack.top/