前言
看了网上很多关于async/await和promise执行顺序的文章,感觉都没有说到点子上,都是根据结果在推测执行顺序。本文带你彻底搞懂这两者的执行顺序。前提是你对async/await和promise本身就已经有了一定的了解。
例题
首先看一下下面这几道例题,思考一下每题的输出结果。
// 例子1
console.log("-------例子1-------");
const p1 = Promise.resolve()
async function foo() {
await p1;
console.log('await');
}
foo()
p1.then(()=>{
console.log('promise');
})
// 例子2
console.log("-------例子2-------");
const p2 = Promise.resolve()
async function foo() {
await p2;
console.log('await');
}
p2.then(()=>{
console.log('promise');
})
foo()
// 例子3
console.log("-------例子3-------");
const p3 = Promise.resolve()
async function foo() {
await 1;
console.log('await');
}
foo()
p3.then(()=>{
console.log('promise');
})
// 例子4
console.log("-------例子4-------");
const p4 = Promise.resolve()
async function foo() {
await 1;
console.log('await');
}
p4.then(()=>{
console.log('promise');
})
foo()
// 例子5
console.log("-------例子5-------");
const p5 = Promise.resolve()
async function foo () {
await p5;
console.log('await')
}
foo()
p5.then(()=>{
console.log('promise');
}).then(()=>console.log(22)).then(()=>console.log(33)).then(()=>console.log(44))
// 例子6
console.log("-------例子6-------");
const p6 = Promise.resolve()
async function foo () {
await p6;
console.log('await')
}
p6.then(()=>{
console.log('promise');
}).then(()=>console.log(22)).then(()=>console.log(33)).then(()=>console.log(44))
foo()
// 例子7
console.log("-------例子7-------");
const p7 = Promise.resolve()
async function foo () {
await 1;
console.log('await')
}
foo()
p7.then(()=>{
console.log('promise');
}).then(()=>console.log(22)).then(()=>console.log(33)).then(()=>console.log(44))
// 例子8
console.log("-------例子8-------");
const p8 = Promise.resolve()
async function foo () {
await 1;
console.log('await')
}
p8.then(()=>{
console.log('promise');
}).then(()=>console.log(22)).then(()=>console.log(33)).then(()=>console.log(44))
foo()
答案如下:
- node版本:v10.15.3
// 例子1
console.log("-------例子1-------");
const p1 = Promise.resolve()
async function foo() {
await p1;
console.log('await');
}
foo()
p1.then(()=>{
console.log('promise');
})
/*
-------例子1-------
promise
await
*/
// 例子2
console.log("-------例子2-------");
const p2 = Promise.resolve()
async function foo() {
await p2;
console.log('await');
}
p2.then(()=>{
console.log('promise');
})
foo()
/*
-------例子2-------
promise
await
*/
// 例子3
console.log("-------例子3-------");
const p3 = Promise.resolve()
async function foo() {
await 1;
console.log('await');
}
foo()
p3.then(()=>{
console.log('promise');
})
/*
-------例子3-------
await
promise
*/
// 例子4
console.log("-------例子4-------");
const p4 = Promise.resolve()
async function foo() {
await 1;
console.log('await');
}
p4.then(()=>{
console.log('promise');
})
foo()
/*
-------例子4-------
promise
await
*/
// 例子5
console.log("-------例子5-------");
const p5 = Promise.resolve()
async function foo () {
await p5;
console.log('await')
}
foo()
p5.then(()=>{
console.log('promise');
}).then(()=>console.log(22)).then(()=>console.log(33)).then(()=>console.log(44))
/*
-------例子5-------
promise
22
await
33
44
*/
// 例子6
console.log("-------例子6-------");
const p6 = Promise.resolve()
async function foo () {
await p6;
console.log('await')
}
p6.then(()=>{
console.log('promise');
}).then(()=>console.log(22)).then(()=>console.log(33)).then(()=>console.log(44))
foo()
/*
-------例子6-------
promise
22
33
await
44
*/
// 例子7
console.log("-------例子7-------");
const p7 = Promise.resolve()
async function foo () {
await 1;
console.log('await')
}
foo()
p7.then(()=>{
console.log('promise');
}).then(()=>console.log(22)).then(()=>console.log(33)).then(()=>console.log(44))
/*
-------例子7-------
await
promise
22
33
44
*/
// 例子8
console.log("-------例子8-------");
const p8 = Promise.resolve()
async function foo () {
await 1;
console.log('await')
}
p8.then(()=>{
console.log('promise');
}).then(()=>console.log(22)).then(()=>console.log(33)).then(()=>console.log(44))
foo()
/*
-------例子8-------
promise
await
22
33
44
*/
- node版本:v14.15.0
// 例子1
console.log("-------例子1-------");
const p1 = Promise.resolve()
async function foo() {
await p1;
console.log('await');
}
foo()
p1.then(()=>{
console.log('promise');
})
/*
-------例子1-------
await
promise
*/
// 例子2
console.log("-------例子2-------");
const p2 = Promise.resolve()
async function foo() {
await p2;
console.log('await');
}
p2.then(()=>{
console.log('promise');
})
foo()
/*
-------例子2-------
promise
await
*/
// 例子3
console.log("-------例子3-------");
const p3 = Promise.resolve()
async function foo() {
await 1;
console.log('await');
}
foo()
p3.then(()=>{
console.log('promise');
})
/*
-------例子3-------
await
promise
*/
// 例子4
console.log("-------例子4-------");
const p4 = Promise.resolve()
async function foo() {
await 1;
console.log('await');
}
p4.then(()=>{
console.log('promise');
})
foo()
/*
-------例子4-------
promise
await
*/
// 例子5
console.log("-------例子5-------");
const p5 = Promise.resolve()
async function foo () {
await p5;
console.log('await')
}
foo()
p5.then(()=>{
console.log('promise');
}).then(()=>console.log(22)).then(()=>console.log(33)).then(()=>console.log(44))
/*
-------例子5-------
await
promise
22
33
44
*/
// 例子6
console.log("-------例子6-------");
const p6 = Promise.resolve()
async function foo () {
await p6;
console.log('await')
}
p6.then(()=>{
console.log('promise');
}).then(()=>console.log(22)).then(()=>console.log(33)).then(()=>console.log(44))
foo()
/*
-------例子6-------
promise
await
22
33
44
*/
// 例子7
console.log("-------例子7-------");
const p7 = Promise.resolve()
async function foo () {
await 1;
console.log('await')
}
foo()
p7.then(()=>{
console.log('promise');
}).then(()=>console.log(22)).then(()=>console.log(33)).then(()=>console.log(44))
/*
-------例子7-------
await
promise
22
33
44
*/
// 例子8
console.log("-------例子8-------");
const p8 = Promise.resolve()
async function foo () {
await 1;
console.log('await')
}
p8.then(()=>{
console.log('promise');
}).then(()=>console.log(22)).then(()=>console.log(33)).then(()=>console.log(44))
foo()
/*
-------例子8-------
promise
await
22
33
44
*/
分析
相信很多人都知道await后面的内容都会被包装在一个promise中。现在有两个疑问需要解决:
- 这个被包装出来的promise内部是如何实现的
- await后面跟常量和本身就是promise有什么区别 解开这两个疑问基本上就知道async/await和promise的执行顺序了。 这里有一篇博文可以解开我们的疑问。
- 原文链接:v8.dev/blog/fast-a…
- 译文链接:www.yuque.com/es2049/blog… 我把这里面的主要结论直接摘取出来:
在Node.js 12之前,await经过V8引擎的编译后,会至少生成三个微任务。
这里面存在冗余的运算,所以后来(Node.js 12)进行了优化。
如果入参是 promise,则原封不动地返回,只封装必要的 promise。这个操作在值已经是 promose 的情况下可以省去一个额外的 promise 和两个微任务。
总结
- 在v10-v12版本,如果await之后是promise,则在外面还会被继续包装promise,在内部会产生三个微任务;如果await之后不是promise,则把该值包装成promise,此时只有一层。
- 在v12版本之后,await之后已经全部都优化成只有一个微任务。