1. 程式人生 > >event loop js事件迴圈 microtask macrotask

event loop js事件迴圈 microtask macrotask

放個面試題,拋個磚:

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') })

不著急揭曉答案,先分析

首先知曉:

js是單執行緒語言

也就是說一次就只能做一件事情。

多數的網站不需要大量計算,程式花費的時間主要集中在磁碟 I/O 和網路 I/O 上面

雖然SSD讀取很快,但和CPU處理指令的速度比起來也不在一個數量級上,而且網路上一個資料包來回的時間更慢(注意過遊戲的延遲嗎)

so: 一些cpu直接執行的任務就成了優先執行主線任務,然後需要io返回資料的任務就成了等待被執行的任務

所以才會有同步任務(synchronous)和非同步任務(asynchronous)之分

同步任務:

在主執行緒上排隊執行的任務,前一個任務執行完畢,才能執行後一個任務;

非同步任務:

不進入主執行緒、而進入”任務佇列”(task queue)的任務,只有”任務佇列”通知主執行緒,某個非同步任務可以執行了,該任務才會進入主執行緒執行。

總之:

只要主執行緒空了,就會去讀取”任務佇列”,這就是JavaScript的執行機制

Microtasks Macrotasks

任務佇列不止一個,還有 microtasks 和 macrotasks

microtasks:

  • process.nextTick
  • promise
  • Object.observe
  • MutationObserver

macrotasks:

  • setTimeout
  • setInterval
  • setImmediate
  • I/O
  • UI渲染
  • 一個事件迴圈(event loop)會有一個或多個任務佇列(task queue)
  • task queue 就是 macrotask queue
  • 每一個 event loop 都有一個 microtask queue
  • task queue == macrotask queue != microtask queue
  • 一個任務 task 可以放入 macrotask queue 也可以放入 microtask queue 中

理解了這些定義之後,再看執行原理:

事件迴圈的順序,決定了JavaScript程式碼的執行順序。它從script(整體程式碼)開始第一次迴圈。之後全域性上下文進入函式呼叫棧。直到呼叫棧清空(只剩全域性),然後執行所有的micro-task。當所有可執行的micro-task執行完畢之後。迴圈再次從macro-task開始,找到其中一個任務佇列執行完畢,然後再執行所有的micro-task,這樣一直迴圈下去。

還要注意一點:

包裹在一個 script 標籤中的js程式碼也是一個 task 確切說是 macrotask。

所以文首面試題的答案為:

start
promise 1
promise 2
setInterval
setTimeout 1
promise 3
promise 4
setInterval
setTimeout 2
promise 5
promise 6

簡單來講,整體的js程式碼這個macrotask先執行,同步程式碼執行完後有microtask執行microtask,沒有microtask執行下一個macrotask,如此往復迴圈至結束