js事件循环 microtask macrotask

上篇文章说了一下js中定时器 setTimeout 和 setInterval 的执行原理。这两个计时器都是异步执行的,这部分体现了js的执行过程。

 

js自身执行的模型是事件循环(event loop)。

js在启动时会创建一个循环,每次循环都会去任务队列(task query)里找要进行的任务。当队列里的一个任务执行完毕,该循环会去找下一个任务去执行。js的执行过程就是该循环不断地执行。像定时器,用户触发的事件,promise 等异步执行的代码,都会按规定往这个任务队列推。

任务队列不是只有一个,有 microtasks 和 macrotasks 之分。macrotask query 就是 task query,每个 macrotask 里都有一个 microtask。js开始执行时,会先取一个 macrotask,然后取里面的 microtask 去执行。当前的 microtask 执行完毕之后,会取下一个 microtask 直到 microtask 执行完,然后退出该 macrotask,去执行下一个 macrotask,然后就一直循环下去。就相当于有一个 task query,而这个队列中的每一个 task,也相当于一个 task query。

macrotask 会放到下一个事件循环中去,而 microtask 会放到当前事件循环的最后,因此我们观察到的现象直观地来说,就是这些异步方法有一个优先级,microtask 要比 macrotask 优先级高,优先级高的会比优先级低的先执行,同优先级的就根据进入队列的时间去执行。所以在同步的代码中,不管 microtask 和 macrotask 谁先放入队列,都是 microtask 先执行,macrotask 后执行。

 

macrotasks: setTimeout   setInterval   setImmediate   I/O   UI渲染

microtasks: Promise   process.nextTick   Object.observe   MutationObserver

 

看一个例子:

 1 console.log('start')
 2 
 3 Promise.resolve().then(() => {
 4     console.log('promise 1')
 5 })
 6 
 7 setTimeout(() => {
 8     console.log('setTimeout 1')
 9     Promise.resolve().then(() => {
10         console.log('promise 2')
11         Promise.resolve().then(() => {
12             console.log('promise 3')
13         }).then(() => {
14             console.log('promise 4')
15         })
16     }).then(() => {
17         setTimeout(() => {
18             console.log('setTimeout 2')
19             Promise.resolve().then(() => {
20                 console.log('promise 5')
21             })
22         }, 0)
23         console.log('promise 6')
24     })
25     console.log('setTimeout 2')
26 }, 0)
27 
28 setTimeout(() => {
29     console.log('setTimeout 3')
30     Promise.resolve().then(() => {
31         console.log('promise 7')
32     })
33     console.log('setTimeout 4')
34 }, 0)
35 
36 Promise.resolve().then(() => {
37     console.log('promise 8')
38 })

 

执行结果为

start
promise 1
promise 8
setTimeout 1
setTimeout 2
promise 2
promise 3
promise 6
promise 4
setTimeout 3
setTimeout 4
promise 7
setTimeout 2
promise 5
 
不知道各位把这个问题弄明白没?
 
 
 

----------------------------------

 

 

 
这个问题一开始我是做错了的,做错的地方为 promise 2 3 4 6 这几个点。后来再看了一遍 promise 的原理,才把它搞明白。
 
 1 Promise.resolve().then(() => {
 2     console.log('promise 1')
 3     Promise.resolve().then(() => {
 4         console.log('promise 2')
 5     }).then(() => {
 6         console.log('promise 3')
 7     })
 8 }).then(() => {
 9     console.log('promise 4')
10 })

我说的那一部分,单独抽出来就是上面这段,其运行结果为

promise 1

promise 2

promise 4

promise 3

这个问题其实是 promise 的原理,我这里就不多说了,大家去看 promise 的原理应该可以找到答案。

posted @ 2017-12-04 18:59  李啸虎  阅读(864)  评论(0编辑  收藏  举报