“这是我参与8月更文挑战的第2天,活动详情查看:8月更文挑战”
与generater的差异
更好的语义
async和await,比起*和yield,语义更清楚。async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果
内置执行器
Generator函数的执行必须靠执行器,所以才有了co模块,而async函数自带执行器。也就是说,async函数的执行,与普通函数一模一样,只要一行。
更广的适用性
co模块约定,yield命令后面只能是Thunk 函数或Promise对象,而async函数的await命令后面,可以是 Promise对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即resolved的 Promise对象)。
返回值是Promise
async函数的返回值是Promise对象,这比 Generator函数的返回值是Iterator对象方便多了。你可以用then方法指定下一步的操作。
例子
当执行到asyncPrint("hello world", 1000);时,遇到了await,这代表了此处99%有异步代码,就会让出控制权,继续执行主线程后面的代码console.log("hello async");,执行栈空了,就会去查看消息(任务)队列(包含微任务和宏任务),先执行全局微任务,微任务执行完毕后,执行宏任务。微任务await timeout(ms);压入执行栈执行,此处会等待1秒(因为要等new Promise((resolve) => { setTimeout(resolve, ms) })返回promise状态也就是执行完resolve()),await执行完毕后,让出控制权,继续执行async中的同步代码,执行 console.log(value);
return new Promise((resolve) => {
setTimeout(resolve, ms)
})
}
async function asyncPrint(value, ms) {
await timeout(ms);
console.log(value);
}
asyncPrint("hello world", 1000);
console.log("hello async");
//输出顺序
// hello async
// hello world
当执行到asyncPrint("hello world", 1000);时,遇到了await,这代表了此处99%有异步代码,就会让出控制权,继续执行主线程后面的代码console.log("hello async");,执行栈空了,执行await setTimeout(function() { console.log(1122) }, 0);,将宏任务setTimeout交给宏任务队列,继续执行async中的同步代码console.log(value);,执行await 2,直接将2放到微任务中;继续执行async中的同步代码console.log(3344);。同步代码执行完毕,执行微任务,微任务清空了,执行宏任务 console.log(1122) 。
function timeout(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms)
})
}
async function asyncPrint(value, ms) {
await setTimeout(function() { console.log(1122) }, 0);
console.log(value);
await 2;
console.log(3344);
}
asyncPrint("hello world", 1000);
console.log("hello async");
//输出顺序
// hello async
// hello world
// 3344
// 1122
async注意事项
- await命令后面的Promise对象,运行结果可能是rejected,所以最好把await命令放在try...catch代码块中。
- 多个await命令后面的异步操作,如果不存在继发(依赖)关系,最好让它们同时触发。
- 第三点,await命令只能用在async函数之中,如果用在普通函数,就会报错。