JS MarcoTasks MicroTasks

JS MarcoTasks MicroTasks

在JS的event loop中,有兩種任務隊列microtasksmacrotaskspromise

microtasksoop

  • process.nextTick
  • Promise
  • Object.observe
  • MutationObserver

macrotaskscode

  • setTimeout
  • setInterval
  • setImmediate
  • I/O(Ajax, fs)
  • UI渲染

在一個事件循環event loop的週期中,一個task應該從macrotask隊列開始執行。當這個macrotask結束後,全部的microtasks將在同一個cycle中執行。
且在microtasks執行時還能夠加入更多的microtask,而後一個一個的執行,直到microtask隊列清空。server

console.log('start')

const interval = setInterval(() => {  
  console.log('setInterval')
}, 0)

setTimeout(() => {  
  console.log('setTimeout 1')
  Promise.resolve()
      .then(() => {
        console.log('promise 3')
      })
      .then(() => {
        console.log('promise 4')
      })
      .then(() => {
        setTimeout(() => {
          console.log('setTimeout 2')
          Promise.resolve()
              .then(() => {
                console.log('promise 5')
              })
              .then(() => {
                console.log('promise 6')
              })
              .then(() => {
                clearInterval(interval)
              })
        }, 0)
      })
}, 0)

Promise.resolve()
    .then(() => {  
        console.log('promise 1')
    })
    .then(() => {
        console.log('promise 2')
    })

event loop1:
macrotasks: [主程序代碼]
microtasks: []隊列

執行macrotasks隊列,也即執行主程序代碼,收集macro或micro的tasks
輸出: 'start'
收集的macrotasks(下次循環的): [setInterval, setTimeout]
收集的microtasks(當前循環的): [Promise]事件

macrotasks隊列執行完畢,這時候microtasks: [Promise]不爲空,執行microtasks隊列
輸出: 'promise1'
輸出 : 'promise2'
這時候microtasks爲空io

下次循環開始以前的隊列狀態
macrotasks: [setInterval, setTimeout]
microtasks: []console

event loop2:
執行macrotasks隊列
執行setInterval
輸出:'setInterval',且收集setInterval到下次循環的macrotasks中
執行setTimeout
輸出:'setTimeout 1',且收集Promise到當前循環的microtasks: [Promise]event

因爲當前循環的microtasks不爲空,執行隊列中的任務Promise
輸出:'promise3'
輸出: 'promise4'
收集setTimeout到下次循環的macrotasks中
這時候microtasks爲空class

下次循環開始以前的隊列狀態
macrotasks: [setInterval, setTimeout]
microtasks: []

event loop3:
執行macrotasks隊列
執行setInterval
輸出: 'setInterval',且收集setInterval到下次循環的macrotasks: [setInterval]中
執行setTimeout
輸出: 'setTimeout2',且收集Promise到當前的microtasks: [Promise]

因爲當前循環的microtasks不爲空,執行隊列中的任務Promise
輸出: 'promise5'
輸出: 'promise6'
清除定時器clearInterval,因此下次循環的macrotasks的setInterval被清除

下次循環開始以前的隊列狀態
macrotasks: []
microtasks: []

event loop4:
因爲macrotasks爲空,和microtasks爲空,程序處於等待狀態。

上面程序總的輸出結果是

// event loop1
start

promise 1
promise 2

// event loop2
setInterval
setTimeout 1

promise 3
promise 4

// event loop3
setInterval
setTimeout 2

promise 5
promise 6

總結

  • 一個循環開始的時候microtasks(大多狀況)是空的,或者說當前循環的microtasks一開始是空的,在macrotasks執行完後可能不爲空
  • microtasks要等到macrotasks隊列執行完畢纔會開始執行,且microtasks的任務在執行的過程當中,是能夠添加任務的,只要當前循環還未結束
  • 在當前循環中收集的macro任務是收集到下一個循環的macrotasks,而當前循環收集的micro任務是收集到當前microtasks中
相關文章
相關標籤/搜索