Promise输出顺序相关问题

题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Promise.resolve()
.then(() => {
console.log(0);
setTimeout(() => {
console.log("宏任务");
}, 0);
// return 4
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);
})
.then(() => {
console.log(7);
})
.then(() => {
console.log(8);
});

答:

1
2
3
4
5
6
7
8
9
10
11
// 输出结果
0;
1;
2;
3;
4;
5;
6;
7;
8;
宏任务;

解析:

| return Promise.resolve(4)会产生一个叫 job 的函数,等到当前执行栈为空的时候会去执行

| 微任务的执行中生成了微任务,那么会继续执行微任务,直到微任务队列为空。

  1. 宏任务队列 1,执行Promise.resolve()
  2. 遇到then()回调,往微任务队列推入以下代码:
1
2
3
4
5
6
7
// 微任务队列加入了以下代码
// 微任务队列1
console.log(0);
setTimeout(() => {
console.log("宏任务");
}, 0);
return Promise.resolve(4);
  1. 仍然在当前宏任务往下执行,执行第二个Promise.resolve()
  2. 遇到then()回调,往微任务队列推入以下代码:
1
console.log(1);

所以此时微任务队列里有两个代码块待执行。队列就是先进先出的原则

1
2
3
4
5
6
7
8
9
// 第一个:A
console.log(0);
setTimeout(() => {
console.log("宏任务");
}, 0);
return Promise.resolve(4);

// 第二个:B
console.log(1);
  1. 此时代码模块里的宏任务都已经执行完了,开始捞取微任务到执行栈中执行。队列里第一个出来的也就是代码:
1
2
3
4
5
console.log(0);
setTimeout(() => {
console.log("宏任务");
}, 0);
return Promise.resolve(4);

输出 0。

注册一个 job,当执行栈为空的时候,job 进入队列。此时执行栈并不为空。A 出栈 B 入栈

6.

1
console.log(1);

输出 1。then 的回调推入微任务队列。B 出栈。执行栈为空。job 也进入微任务队列

函数是:
此时的微任务队列就有两个函数

1
2
3
4
5
6
7
8
9
// 第一个
.then(() => {
console.log(2);
})

// 第二个,job
(4) => {
this.resolvePromise(promise2, 4, resolve, reject);
};

  1. 输出 2 将它的回调函数推入微任务队列
1
2
3
.then(() => {
console.log(3);
})

再去执行

1
2
3
(4) => {
this.resolvePromise(promise2, 4, resolve, reject);
};

这个函数会将

1
2
3
(res) => {
console.log(res);
};

推入微任务队列

  1. 输出 3 和 4

输出 3 的回调再次推入微任务

1
2
3
.then(() => {
console.log(5);
})
  1. 输出 5

  2. 后续输出原理相同,输出 6,7,8

  3. 此时没有回调微任务进栈了,开始清空宏任务队列,也就是 setTimeout,输出宏任务


Promise输出顺序相关问题
https://zouhualu.github.io/20220329/Promise输出顺序相关问题/
作者
花鹿
发布于
2022年3月29日
许可协议