看到这样一段代码
Promise.resolve().then(() => {
console.log(0);
return Promise.resolve(4) // p2
}).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);
})
result: 0123456
对此结果非常疑惑,百思不得其解,本来觉得结果应该是0142356
最后经过多方搜索,在知乎山看到这样一个问题关于promise输出顺序的疑问?, 紫云飞大大的回答解决了我的疑惑,但是大大的解答太过抽象,我也是自己摸索好久才万全明白,在此记录一下。
问题的关键在于在promise内部返回一个thenable对象会发生什么?
1、promise的then是一个microtask微任务
2、promise p return
一个promise p2的时候,其实是将这个p2的then加入到了微任务队列中,同时将p的resolve和reject传给p2
3、p2中的then全部调用完成之后,会将p的resolve放入微任务队列,resolve完成之后,这个时候p的状态才会变化,继续执行p的then
所以以上代码的执行过程就是:
输出 |
微任务队列 |
|
[0, 1] |
0 |
[1, p2-then] |
1 |
[p2-then, 2] |
|
[2, resolve] |
2 |
[resolve, 3] |
|
[3, 4] |
3 |
[4, 5] |
4 |
[5, 6] |
5 |
[6] |
6 |
[] |
一下是几个例子,加深一下理解(队列中的元素对应的是元素所在的then
)
Example1
new Promise((resolve, reject) => {
console.log("外部promise");
resolve();
})
.then(() => {
console.log("外部第一个then");
return new Promise((resolve, reject) => {
console.log("内部promise");
resolve();
})
.then(() => {
console.log("内部第一个then");
})
.then(() => {
console.log("内部第二个then");
});
})
.then(() => {
console.log("外部第二个then");
});
输出 |
微任务队列 |
外部promise |
[外部第一个then] |
外部第一个then |
[] |
内部promise |
[内部第一个then] |
内部第一个then |
[内部第二个then] |
内部第二个then |
[resolve] |
|
[外部第二个then] |
外部第二个then |
[] |
Example2
new Promise((resolve, reject) => {
console.log("外部promise");
resolve();
})
.then(() => {
console.log("外部第一个then");
new Promise((resolve, reject) => {
console.log("内部promise");
resolve();
})
.then(() => {
console.log("内部第一个then");
})
.then(() => {
console.log("内部第二个then");
});
})
.then(() => {
console.log("外部第二个then");
});
输出 |
微任务队列 |
外部promise |
[外部第一个then] |
外部第一个then |
[] |
内部promise |
[内部第一个then] |
|
[内部第一个then, 外部第二个then] |
内部第一个then |
[外部第二个then, 内部第二个then] |
外部第二个then |
[内部第二个then] |
内部第二个then |
[] |
Example3
new Promise((resolve, reject) => {
console.log("外部promise");
resolve();
})
.then(() => {
console.log("外部第一个then");
let p = new Promise((resolve, reject) => {
console.log("内部promise");
resolve();
})
p.then(() => {
console.log("内部第一个then");
})
p.then(() => {
console.log("内部第二个then");
});
})
.then(() => {
console.log("外部第二个then");
});
输出 |
微任务队列 |
外部promise |
[外部第一个then] |
外部第一个then |
[] |
内部promise |
[内部第一个then] |
|
[内部第一个then,内部第二个then] |
|
[内部第一个then, 内部第二个then, 外部第二个then] |
内部第一个then |
[内部第二个then, 外部第二个then] |
内部第二个then |
[外部第二个then] |
外部第二个then |
[] |
Example4
let p = new Promise((resolve, reject) => {
console.log("外部promise");
resolve();
})
p.then(() => {
console.log("外部第一个then");
new Promise((resolve, reject) => {
console.log("内部promise");
resolve();
})
.then(() => {
console.log("内部第一个then");
})
.then(() => {
console.log("内部第二个then");
});
})
p.then(() => {
console.log("外部第二个then");
});
输出 |
微任务队列 |
外部promise |
[外部第一个then, 外部第二个then] |
外部第一个then 内部promise |
[外部第二个then, 内部第一个then] |
外部第二个then |
[内部第一个then, 内部第二个then] |
内部第一个then |
[内部第二个then] |
内部第二个then |
[] |
Example5
new Promise((resolve, reject) => { // p
console.log('外部promise');
resolve();
})
.then(() => {
console.log('外部第一个then');
new Promise((resolve, reject) => { // p2
console.log('内部promise');
resolve();
})
.then(() => {
console.log('内部第一个then');
return Promise.resolve(); // p3
})
.then(() => {
console.log('内部第二个then');
})
})
.then(() => {
console.log('外部第二个then');
})
.then(() => {
console.log('外部第三个then');
})
输出 |
微任务队列 |
外部promise |
[外部第一个then] |
外部第一个then 内部promise |
[内部第一个then] |
|
[内部第一个then, 外部第二个then] |
内部第一个then |
[ 外部第二个then, p3-then] |
外部第二个then |
[p3-then, 外部第三个then] |
|
[外部第三个then, p2-resolve] |
外部第三个then |
[p2-resolve] |
|
[内部第二个then] |
内部第二个then |
[] |
Example6
new Promise((resolve, reject) => { // p
console.log("外部promise");
resolve();
})
.then(() => {
console.log("外部第一个then");
new Promise((resolve, reject) => { // p2
console.log("内部promise");
resolve();
})
.then(() => {
console.log("内部第一个then");
})
.then(() => {
console.log("内部第二个then");
});
return new Promise((resolve, reject) => { // p3
console.log("内部promise2");
resolve();
})
.then(() => {
console.log("内部第一个then2");
})
.then(() => {
console.log("内部第二个then2");
});
})
.then(() => {
console.log("外部第二个then");
});
输出 |
微任务队列 |
外部promise |
[外部第一个then] |
外部第一个then 内部promise |
[内部第一个then] |
内部promise2 |
[内部第一个then, 内部第一个then2] |
内部第一个then |
[内部第一个then2, 内部第二个then] |
内部第一个then2 |
[内部第二个then, 内部第二个then2] |
内部第二个then |
[内部第二个then2] |
内部第二个then2 |
[p-resolve] |
|
[外部第二个then] |
外部第二个then |
[] |
Example7
new Promise((resolve, reject) => { // p
console.log("外部promise");
resolve();
})
.then(() => {
console.log("外部第一个then");
new Promise((resolve, reject) => { // p2
console.log("内部promise");
resolve();
})
.then(() => {
console.log("内部第一个then");
})
.then(() => {
console.log("内部第二个then");
});
return new Promise((resolve, reject) => { // p3
console.log("内部promise2");
resolve();
})
.then(() => {
console.log("内部第一个then2");
})
.then(() => {
console.log("内部第二个then2");
});
})
.then(() => {
console.log("外部第二个then");
});
输出 |
微任务队列 |
外部promise |
[外部第一个then] |
外部第一个then 内部promise |
[内部第一个then] |
内部promise2 |
[内部第一个then, 内部第一个then2] |
内部第一个then |
[内部第一个then2, 内部第二个then] |
内部第一个then2 |
[内部第二个then, 内部第二个then2] |
内部第二个then |
[内部第二个then2] |
内部第二个then2 |
[p-resolve] |
|
[外部第二个then] |
外部第二个then |
[] |
2021年8月31日
最近手动写了一遍Promise,可能有点晚。但是明白了为什么promise返回一个promise的时候会需要等一下才能显示,因为Promise的resolvePromise(x, promise, resolve, reject)方法,如果x是一个promise,那么会调用一次then.call(x, y => {resolvePromise(y, promise, resolve, reject)}, reject), then是微服务,所以需要再次进入微服务队列排队,所以会有这样的现象
网友评论