詳解高級前端面試常問的EventLoop

首先啥是EventLoop?

整個js這種運行機制又稱爲Event Loop(事件循環)node

EventLoop又分爲瀏覽器端和node端兩種

上代碼感覺一下瀏覽器

setTimeout(() => {
        console.log(1)
        Promise.resolve(3).then(data => console.log(data))
      }, 0)
      
setTimeout(() => {
        console.log(2)
      }, 0)
//瀏覽器 1 3 2
//node 1 2 3
複製代碼

瀏覽器的EventLoop

首先就是執行時會有一個棧 而後有一個事件隊列和微任務空間(本身命名的)bash

當咱們的代碼從上到下同步執行時,遇到setTimeout就記時,當時間到時就把此事件放到事件隊列中,遇到微任務就把微任務放到微任務空間,代碼會繼續向下執行,直到同步代碼執行完畢。異步

完畢後,會看看微任務空間中有沒有微任務,有就把微任務空間中的微任務所有執行,而後去隊列中取咱們的事件執行,執行時如有微任務繼續放到微任務空間,當此事件執行完畢,還會把微任務空間中的微任務所有執行完畢,而後再去取隊列中的異步任務。。。。反覆循環oop

有圖有真相(是否是很醜!醜也別說出來)ui

微任務和宏任務

  • 微任務 Promise的then, (MutationObserver)
  • 宏任務 setInterval, setTimeout, setImmediate(ie), MessageChannel

node端的EventLoop

想上個醜圖spa

再來段文字描述 爭取把本身繞暈

  • setTimeout 和 setImmediate 執行順序不固定 取決於node的準備時間

setImmediate 設計在poll階段完成時執行,即check階段; setTimeout 設計在poll階段爲空閒時,且設定時間到達後執行;但其在timer階段執行 其兩者的調用順序取決於當前event loop的上下文,若是他們在異步i/o callback以外調用(在i/o內調用由於下一階段爲check階段),其執行前後順序是不肯定的,須要看loop的執行前的耗時狀況設計

  • 上圖每個方框都對應一個事件隊列,當event loop執行到某個階段時會將當前階段對應的隊列依次執行。當隊列執行完畢或者執行的數量超過上線時,會轉入下一個階段
  • 微任務是在切換對列是執行

廢話很少說,上代碼code

setImmediate(() => {
  console.log('setImmediate1')  
  setTimeout(() => {
    console.log('setTimeout1')
  }, 0);
})
setTimeout(()=>{
  console.log('setTimeout2')
  setImmediate(()=>{
    console.log('setImmediate2')
  })
},0);
//首先setImmediate和setTimeout執行順序不固定 
//因此setImmediate1和setTimeout2,打印順序不定
//假設 setImmediate1先打印   有兩種順序
//1.執行順序是 setImmediate1  setTimeout2  setTimeout1 setImmediate2
//2.執行順序是 setImmediate1  setTimeout2  setImmediate2 setTimeout1
// 1.setImmediate1打印後把setTimeout1放進timer隊列 而後執行setTimeout2 這時候把setImmediate2放進check隊列中  打印setTimeout2 發現timer中還有setTimeout1 他就會把timer對列中的執行完 纔會執行下一隊列的代碼
//而後打印setTimeout1, 切換對列到check  打印setImmediate2
//2. setImmediate1打印後把setTimeout1放進timer隊列 而後執行setTimeout2 這時候把setImmediate2放進check隊列中  打印setTimeout2 這個時候node執行過快setTimeout1尚未到時間,因此切換對列執行setImmediate2 而後是setTimeout1
//setTimeout第二個參數雖然是0,可是都有默認時間通常是4ms左右
複製代碼

再來一題cdn

setImmediate(() => {
  console.log('setImmediate1')  
  setTimeout(() => {
    console.log('setTimeout1')
  }, 0);
})
setTimeout(()=>{
  console.log('setTimeout2')
  process.nextTick(()=>console.log('nextTick'))
  setImmediate(()=>{
    console.log('setImmediate2')
  })
},0);
//假設setImmediate1先
//setImmediate1  setTimeout2 setTimeout1  nextTick setImmediate2
//setImmediate1  setTimeout2 nextTick setImmediate2 setTimeout1
//微任務會在切換對列時執行  上面從timer對列切換到check對列時nextTick執行
//上面一題明白了這一個也明白了

複製代碼

再來一題

let fs = require('fs');
fs.readFile('./1.txt',function () {
  console.log(1);
  setTimeout(() => {
    console.log('setTimeout')
  }, 0);
  setImmediate(() => {
    console.log('setImmediate')
  });
});

//順序固定 1 setImmediate setTimeout
// 爲何呢?看上面的圖  首先readFile確定是poll對列   執行時把setTimeout setImmediate放到各自隊列 而後按上下順序查找對列  查找到check隊列發現有 就把setImmediate打印出  而後順序檢查下一隊列close沒有 循環 再次從上往下找  直到timer打印setTimeout
複製代碼

以上內容是本人試出來的 mac vscode

微任務有兩種 nextTick和then 那麼這兩個誰快呢?

Promise.resolve('123').then(res=>{
   console.log(res);
   
 })
  process.nextTick(() => console.log('nextTick'))
  
  //順序  nextTick 123
  //很明顯  nextTick快
  
複製代碼
相關文章
相關標籤/搜索