nodejs 中的异步执行顺序

前段时间无聊,给朋友讲 Node.js 的异步执行的问题,今天翻到代码和解释,做个记录

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
36
37
// js 事件循环中的异步队列有两种:
// - macro(宏任务)队列,比如: setTimeout、setInterval、 setImmediate、script(整体代码)、 I/O 操作、UI 渲染等。
// - micro(微任务)队列,比如:process.nextTick、Promise、MutationObserver 等。
// 完整的 Event Loop 过程。
// 初始状态:micro 队列空,macro 队列里有且只有一个 script 脚本(整体代码为宏任务);
// 执行 script 代码,创建的宏任务推到宏任务调用栈中,创建的微任务推到微任务调用栈中;【宏任务阶段】
// 执行微任务,调出当前微任务栈的所有微任务,一次执行,其中如果有宏任务推到宏任务栈中【微任务阶段】
// 执行宏任务,调出当前宏任务栈中的第一个宏任务,其中创建的微任务推到微任务栈中【宏任务阶段】
// 如果代码未结束,循环执行 3,4 步骤

let timeout = cb => setTimeout(cb ,0)
let f = flag => new Promise(resolve => {
console.log('start ', flag)
resolve(flag)
}).then(flag => {
console.log('p-' + flag)
// >>>??
setTimeout(function __inner__() {
console.log('inner ' + flag)
})
}).then(flag => {
console.log('p-debug')
})

// 宏任务
timeout(function __hello__() {
console.log('hello')
// 微任务
f(3)
})
// 宏任务
timeout(function __world__() {
console.log('world')
})
// 微任务
f(1)
f(2)

代码都是从上往下执行,执行完后,会从微任务队列把所有微任务执行完,再从宏任务队列取出一个宏任务执行,再从微任务队列中取出所有微任务并执行。

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
27 行,注册__hello__宏任务
宏任务:[__hello__]
微任务:[]

33 行注册__world__宏任务
宏任务:[__hello__,__world__]
微任务:[]

37 行调用一个 Promise,执行

start 1

并注册一个微任务 then1.1

宏任务:[__hello__,__world__]
微任务:[then1.1]

38 行调用一个 Promise,执行

start 2

并注册一个微任务 then2.1

宏任务:[__hello__,__world__]
微任务:[then1.1,then2.1]

同步执行完毕


从微任务中将所有的微任务取出并执行

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
宏任务:[__hello__,__world__]
微任务:[then2.1]
run: then1.1

打印 p-1

注册一个__inner 1__

宏任务:[__hello__,__world__,__inner 1__]
微任务:[]
run: then1.1 then2.1

then1.1 执行完毕,注册一个 then1.2,执行微任务队列中的下一个任务 then2.1

宏任务:[__hello__,__world__,__inner 1__]
微任务:[then1.2]
run: then2.1

打印 p-2

注册一个__inner 2__

宏任务:[__hello__,__world__,__inner 1__,__inner 2__ ]
微任务:[then1.2]
run: then2.1

then2.1 执行完毕,注册一个 then2.2

宏任务:[__hello__,__world__,__inner 1__,__inner 2__ ]
微任务:[then1.2,then2.2]
run:

取出微任务队列
宏任务:[__hello__,__world__,__inner 1__,__inner 2__ ]
微任务:[]
run: then1.2,then2.2

分别打印 p-debug * 2

微任务队列为空,取出一个宏任务__hello__

宏任务:[__world__,__inner 1__,__inner 2__ ]
微任务:[]
run: __hello__

打印 hello

遇到一个 f3,得到

start 3

并将 then3.1 加入微任务队列,__hello__执行完毕

宏任务:[__world__,__inner 1__,__inner 2__ ]
微任务:[then3.1]
run:

取出所有微任务执行 :then3.1

打印 p-3

将__inner 3__加入宏任务队列

宏任务:[__world__,__inner 1__,__inner 2__,__inner 3__ ]
微任务:[]
run: then3.1

then3.1 下面还有微任务,继续执行

p-debug

微任务执行完毕,取出一个宏任务

宏任务:[__inner 1__,__inner 2__,__inner 3__ ]
微任务:[]
run: __world__

打印 world

微任务队列为空,执行下一个宏任务

宏任务:[__inner 2__,__inner 3__ ]
微任务:[]
run: __inner 1__

打印 inner 1

微任务队列为空,执行下一个宏任务

宏任务:[__inner 3__ ]
微任务:[]
run: __inner 2__

打印 inner 2

微任务队列为空,执行下一个宏任务

宏任务:[]
微任务:[]
run: __inner 3__

打印 inner 3

宏任务和微任务队列全部清空,程序结束


nodejs 中的异步执行顺序
https://bubao.github.io/posts/f05aaded.html
作者
一念
发布于
2021年11月18日
许可协议