这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战
1.引入async和await的原因
①用promise解决异步函数仍然不够简洁
②promise的then链传递参数仍然很复杂
promise用来解决回调函数多层嵌套,async/await用来优化promise的多个then链调用和传参问题。
2.async/await
从操作形式上看:Generator 函数的语法糖。async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await。
从功能上看:await命令就是内部then命令的语法糖。
2.1 async函数:
声明某个函数是异步函数。
作用:async 函数返回的是一个 Promise 对象。
所以如果某个函数返回的本身就是promise的话,不需要使用async声明。
如果async声明的函数不是promise对象,async 会把这个直接量通过 Promise.resolve() 封装成 Promise 对象。即使没有返回值,async也会返回Promsie.resolve(undefined)。
2.2 await关键字:
await只能写在async函数中
await是一个运算符, 与其后面表达式的值进行运算得到最终结果,(我们可以定义一个变量接受这个结果,传递给下一个异步操作作为参数)。
十分十分重要!!!!!! :
- await后面不是一个 Promise 对象: await会
阻塞后面的代码,先执行async外面的同步代码,同步代码执行完,再回到async内部,把这个非promise的东西,作为 await表达式的结果。 - await后面是一个 Promise 对象: await 会
阻塞后面的代码,先执行async外面的同步代码,等着 Promise 对象 resolve,然后得到 resolve 的值,作为 await 表达式的运算结果。
例:有三个步骤,但每一个步骤都需要之前每个步骤的结果。
function step1(n) {
console.log(`step1 with ${n}`);
return takeLongTime(n);
}
function step2(m, n) {
console.log(`step2 with ${m} and ${n}`);
return takeLongTime(m + n);
}
function step3(k, m, n) {
console.log(`step3 with ${k}, ${m} and ${n}`);
return takeLongTime(k + m + n);
}
写成 Promise 方式实现:
function doIt() {
console.time("doIt");
const time1 = 300;
step1(time1)
.then(time2 => {
return step2(time1, time2)
.then(time3 => [time1, time2, time3]);
})
.then(times => {
const [time1, time2, time3] = times;
return step3(time1, time2, time3);
})
.then(result => { console.log(`result is ${result}`);
console.timeEnd("doIt");
});
}
doIt();
写成async/await:
async function doIt() {
console.time("doIt");
const time1 = 300;
const time2 = await step1(time1);
const time3 = await step2(time1, time2);
const result = await step3(time1, time2, time3);
console.log(`result is ${result}`);
console.timeEnd("doIt");
}
doIt();
2.3async函数的优点(改进):
- 更好的语义,将异步操作的代码同步化
- 对比promise的then链传递参数更方便
- 返回值是promise对象,可以用then方法指定下一步的操作。
参考:
一道面试题目的执行顺序: