async function name([param[, param[, ... param]]]) { statements }
async 函数会返回一个 Promise 对象,如果在函数中 return 一个直接量,async 会把它通过 Promise.resolve() 封装成 Promise 对象;当 async 函数抛出异常时,Promise 的 reject 方法也会传递这个异常值。
async function hello() {
return 'hello, world';
}
console.log(hello()); // Promise { 'hello, world' }
async function error() {
throw 'error';
}
console.log(error()); // Promise { 'error' }
[return_value] = await expression;
await 会暂停当前 async function 的执行,等待 Promise 处理完成,若成功,其回调的 resolve 函数的参数作为 await 表达式的值,然后继续执行 async function;否则把 Promise 的异常原因抛出;若 await 后的表达式的值不是Promise,则返回该值本身。
function timeout(n) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(n + 200);
}, n)
})
}
async function foo() {
let x = await timeout(500);
console.log(x); // 700
}
foo();
注:await 关键字只有在 async function 中有效,如果在这之外使用 await,只会得到一个语法错误。
async 函数调用不会造成阻塞,但是执行到 await 时,await 会阻塞后面代码的运行,等待异步操作结束,获得返回值
function asyFun() {
return new Promise((resolve) => {
resolve('resolve');
});
}
async function foo() {
console.log('async Function starts')
let result = await asyFun();
console.log(result);
}
foo();
console.log('after async Function');
// async Function starts
// after async Function
// resolve
注:因为 await 会阻塞其后代码运行,所以多个 await 命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。
async / await 的目的是简化使用多个 Promise 时的同步行为,并对一组 Promise 执行某些操作。
对于一些需要异步返回值作为参数的操作,使用 async / await 就会很方便
function timeout(n) {
return new Promise((resolve, reject) => {
// 一些异步操作
setTimeout(() => {
resolve(n + 200);
}, n)
})
}
const time1 = 500;
function takeALongTime() {
timeout(time1)
.then(time2 => {
console.log(time1, time2);
return timeout(time2).then( time3 => [time1, time2, time3]);
})
.then(times => {
const [time1, time2, time3] = times;
console.log(time1, time2, time3);
return timeout(time3);
})
.then(result => {
console.log('result', result);
})
}
takeALongTime();
如果使用 Promise,在传递参数时就会很麻烦,需要不断地返回并在下一个.then中接收,如果使用 async / await 的话,代码就会变得相对直观,可以像写同步代码一样写,将返回值储存在变量中
const time1 = 500;
async function takeALongTime() {
console.log('start async');
let time2 = await timeout(500);
console.log(time1, time2);
let time3 = await timeout(time2);
console.log(time1, time2, time3)
let result = await timeout(time3);
console.log('result', result);
}
takeALongTime();
最好将 await 放在 try ... catch 中防止出错
function asyFun() {
return new Promise((resolve) => {
resolve('resolve');
});
}
const makeRequest = async () => {
try{
await asyFun();
await asyFun();
await asyFun();
throw new Error("error");
} catch(error) {
console.log(error);
}
};
makeRequest();
//Error: error
// at makeRequest (D:\StudyFiles\asynchronous\promiseTest.js:71:15)
// ...
因为async 函数可以保留运行堆栈,错误可以定位到 makeRequest() 函数
但是如果用 .then() 的话
const makeRequest = () => {
return asyFun()
.then(() => asyFun())
.then(() => asyFun())
.then(() => asyFun())
.then(() => {
throw new Error("error");
});
};
makeRequest().catch(err => {
console.log(err);
});
// Error: error
// at asyFun.then.then.then.then (D:\StudyFiles\asynchronous\promiseTest.js:84:19)
// ...
因为异步执行,抛出错误时 makeRequest 函数已经执行完毕,错误只会定位在 asyFun 中。
MDN async function 文档
MDN await 文档
阮一峰 async 教程
https://segmentfault.com/a/1190000007535316
https://blog.fundebug.com/2017/04/04/nodejs-async-await/
https://juejin.im/post/5a3c68426fb9a0451969c58e