resolve(Promise对象)会多出两个微任务
# 0.前言
之前虽然看过PromiseA+源码,结果昨天晚上碰上这道题懵了。
Promise.resolve().then(() => {
console.log(0)
return Promise.resolve(4)
}).then(res => {
console.log(res)
})
Promise.resolve().then(() => {
console.log(1)
}).then(() => {
console.log(2)
}).then(() => {
console.log(3)
}).then(() => {
console.log(5)
}).then(() => {
console.log(6)
})
// 结果: 1 2 3 4 5 6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
相应的知乎解答:https://www.zhihu.com/question/453677175 (opens new window)。
看了大神们的解答,我也来做出相应的理解与分析:
# 1.解答
顺序执行 0
和 1
应该没什么问题,所以现在问题变成了为什么resolve(Promise)
为什么产生了 2 次微任务(microtask
)?
知乎评论里有人说:根据 promise/A+ ,结果应该为 0 1 2 4 3 5 6
,也就是根据Promise/A+
标准只产生了1次micro task
。
按照PromiseA+
的规范,此处应该是2.3.2
标准:If x is a promise
,根据A+准则的源码是以这么处理的:
- 遇到
.then
就创建一pending
状态的Promise
保存起来。 - 如果是一个普通的
number
类型,则直接用Promise.resolve(number)
即可。 如果是promise
类型的话,需要做一个状态同步操作,代码如下: 其中x
是接收的已经resolved
的Promise
,即(Promise.resolve(4))
,而this
指向我们刚创建的pending
状态的Promise
。
// + micro task: 同步两个Promise的状态。
resolveWithPromise(x) {
x.then(
result => {
this.resolve(result); // promise将结果给resolve
},
reason => {
this.reject(reason);
}
)
};
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
也就是说,这1个micro task
的作用就是同步状态。
至于还有一个微任务的产生原因是来自:v8
和PromiseA+
规范的差异。
v8
中的Promie
实现是通过C++
编写的,与promise/A+
规范的不同之处在于,v8
并没有对x is a promise
的情况做处理,而是只有对x is an object
的处理。所以多了一步micro task
:作用就是将 resolveWithPromise => resolveWithThenableObject
,伪代码如下:
if(x instanceOf MyPromise){
createPromiseResolveThenableJob // + micro task
}
1
2
3
2
3
# 2.总结
面试的时候只需要简单记住:如果resolve()
的括号内的结果是一个promise
的话,会多执行2个micro task
。
# 3.类似的题目
new Promise(resolve => {
let resolvedPromise = Promise.resolve()
resolve(resolvedPromise)
}).then(() => {
console.log('resolvePromise resolved')
})
Promise.resolve()
.then(() => { console.log('promise1') })
.then(() => { console.log('promise2') })
.then(() => { console.log('promise3') })
// 结果是:'resolvePromise resolved' 是在 'promise2' 后面打印出来的。
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 参考资料:
编辑 (opens new window)
上次更新: 2022/04/06, 15:04:00