JS运行机制

JS运行机制图解

  1. 整体的script(作为第一个宏任务)开始执行的时候,会把所有代码分为两部分:“同步任务”、“异步任务”;
  2. 同步任务会直接进入主线程依次执行;
  3. 异步任务会再分为宏任务和微任务;
  4. 宏任务进入到Event Table中,并在里面注册回调函数,每当指定的事件完成时,Event Table会将这个函数移到Event Queue中;
  5. 微任务也会进入到另一个Event Table中,并在里面注册回调函数,每当指定的事件完成时,Event Table会将这个函数移到Event Queue中;
  6. 当主线程内的任务执行完毕,主线程为空时,会检查微任务的Event Queue,如果有任务,就全部执行,如果没有就执行下一个宏任务;
  7. 上述过程会不断重复,这就是Event Loop事件循环;

*只要主线程空了,就会去读取”任务队列”,这就是JavaScript的运行机制。这个过程会不断重复。

其他基础知识提前了解

  1. js中的异步操作(Tip:new Promise是会进入到主线程中立刻执行)
  • setTimeOut
  • setInterval
  • ajax
  • promise
  • I/O
  1. 宏任务 or 微任务(Tip:promise.then属于微任务)
  • 宏任务(macro-task):整体代码script、setTimeOut、setInterval
  • 微任务(micro-task):promise.then、promise.nextTick(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
console.log(1)
setTimeout(function() { // timer1
console.log(2)
}, 1000)

setTimeout(function() { // timer2
console.log(3)
setTimeout(function() { // timer3
console.log(4)
})
})

new Promise(function(resolve) {
console.log(5)
setTimeout(function() { // timer4
console.log(6)
}, 200)
setTimeout(function() { // timer5
console.log(7)
})
resolve()
}).then(function() {
setTimeout(function() { // timer6
console.log(8)
})
console.log(9)
})

console.log(10)

//执行结果
//1,5,10,9,3,7,8,4,6,2

解析(按执行顺序解释):
1.console.log(1)是同步任务,直接执行,打印1;
2.第一个setTimeout是异步任务且宏函数,记做timer1(1000 ms)放到宏函数队列;
3.第二个setTimeout是异步任务且宏函数,记做timer2(0 ms)放到宏函数队列。里面的代码暂时不会执行到;
4.new Promise是同步任务,直接执行,打印5;
5.new Promise里的第一个setTimeout是异步任务且宏函数,记做timer4(200 ms)放到宏函数队列;
6.new Promise里的第二个setTimeout是异步任务且宏函数,记做timer5(0 ms)放到宏函数队列;
7.new Promise里的resolve()函数调用的是promise.then是是异步任务且微函数,放到微函数队列。promise.then里面的代码暂时不会执行;
8.console.log(10)是同步任务,直接执行,打印10;
9.主线程执行完毕,开始执行任务队列,检查微任务队列(micro-task Event Table)中,有Promise.then,执行微任务,发现有setTimeout是异步任务且宏函数,记做timer6放到宏函数队列;
10.console.log(9)是同步任务,直接执行,打印9;
11.微任务执行完毕,第一次循环结束;
12.检查宏任务队列(macro-task Event Table),里面有timer1、timer2、timer4、timer5、timer6,五个定时器宏任务,按照定时器延迟时间得到可以执行的顺序,即Event Queue:timer2、timer5、timer6、timer4、timer1;
13.取出排在第一个的timer2,console.log(3)同步任务,直接执行,打印3
14.timer2中的setTimeout是异步任务且是宏函数,记做timer3,放入宏任务队列(macro-task Event Table)中,且现在执行顺序变为timer5、timer6、timer3,timer4、timer1;
15.没有微任务,第二次Event Loop结束
16.取出timer5执行,console.log(7)同步任务,直接执行,打印7;
17.没有微任务,第三次Event Loop结束;
18.取出timer6执行,console.log(8)同步任务,直接执行,打印8;
19.没有微任务,第四次Event Loop结束;
20.取出timer3执行,console.log(4)同步任务,直接执行,打印4;
21.没有微任务,第四次Event Loop结束;
22.取出timer4执行,console.log(6)同步任务,直接执行,打印6;
23.没有微任务,第四次Event Loop结束;
24.取出timer1执行,console.log(2)同步任务,直接执行,打印2;
25.没有微任务,也没有宏任务,第五次Event Loop结束;
26.结果:1,5,10,9,3,7,8,4,6,2

参考文章

1.js运行机制详解(Event Loop)