开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第9天,点击查看活动详情
前言
学习浏览器环境的事件循环机制离不开 Promise,最近在看相关内容的时候发现两道Promise相关的非常考察细节的面试题。
关键点:return Promise.resolve() 会注册2个空的微任务,可以理解为1个是用于判断return的Promise对象的状态,1个是状态判断后自动注册的空微任务
题1
Promise.resolve()
.then(() => { // 设为 thenA
console.log(0);
return Promise.resolve().then(()=>{console.log('return后的then')}
return Promise.resolve(4); // 重/难 点
})
.then((res) => { // // 设为 thenB
console.log(res);
});
Promise.resolve()
.then(() => { // 设为 thenC
console.log(1);
})
.then(() => { // 设为 thenD
console.log(2);
})
.then(() => { // 设为 thenE
console.log(3);
})
.then(() => { // 设为 thenF
console.log(5);
})
.then(() => { // 设为 thenG
console.log(6);
});
执行结果:0、1、2、3、4、5、6
执行步骤分析:
设 浏览器微任务队列为:microtaskQueue = 【】
- 第一个
Promise.resolve():注册thenA任务,加入微任务队列。此时 microtaskQueue = 【thenA】 - 第二个
Promise.resolve(): 注册thenC任务,加入微任务队列。此时 microtaskQueue = 【thenA,thenC】 - 执行栈中无任务运行,按入队顺序执行微任务队列的任务:
thenA()、thenC() - 执行
thenA():输出 0,执行到return Promise.resolve(),此时还不会注册thenB任务。return Promise.resolve()后没有定义then方法,那么此时会以resolve([value])的value值(此处为undefined) 注册一个空的微任务,并加入队列。此时 microtaskQueue = 【thenC,thenEmpty】 - 执行
thenC():输出 1,注册thenD。此时 microtaskQueue = 【thenEmpty,thenD】 - 执行
thenEmpty():会 自动注册一个空的微任务,此时 microtaskQueue = 【thenD,thenEmpty2】 - 执行
thenD():输出 2,注册thenE。此时 microtaskQueue = 【thenEmpty2,thenE】 - 执行
thenEmpty2():空任务,无代码执行。此时return Promise.resolve()语句执行完毕,注册thenB。此时 microtaskQueue = 【thenE,thenB】 - 执行
thenE():输出 3,注册thenF。此时 microtaskQueue = 【thenB,thenF】 - 执行
thenB(res):输出 4,res接收的是thenA方法中resolve的值。此时 microtaskQueue = 【thenF】 - 执行
thenF():输出 5,注册thenG。此时 microtaskQueue = 【thenG】 - 执行
thenG():输出 6。
巩固一下
// 原题是这样的:
async function async1() {
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2 end');
return Promise.resolve().then(() => {
console.log('async2 end1');
})
}
// async await 是语法糖,也可以改写成下面这样
function async1() {
return new Promise((resolve, reject) => {
async2().then(() => {
console.log('async1 end');
})
})
}
function async2() {
return new Promise((resolve, reject) => {
console.log('async2 end');
resolve(Promise.resolve().then(() => {
console.log('async2 end1');
}))
})
}
async1();
new Promise(resolve => {
console.log('Promise');
resolve();
}).then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2')
}).then(function() {
console.log('promise3')
}).then(function() {
console.log('promise4')
})
关键点:
- 执行
return Promise.resolve(),创建一个Promise实例,将Promise实例设置为resolve状态,这个Promise.resolve()是同步的,且该Promise已经完成了,并不会影响到其他then的注册 return Promise.resolve()会注册 2 个空的微任务,可以理解为 1 个是用于判断return的Promise对象的状态,1个是状态判断后自动注册的空微任务
参考资料
下面两篇文章都是从V8源码层面对这类问题的讲解,值得一看(评论区也非常值得一看👍)