开启掘金成长之旅!这是我参与「掘金日新计划 · 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
源码层面对这类问题的讲解,值得一看(评论区也非常值得一看👍)