js的事件循環機制和任務隊列

 

上篇講異步的時候,提到了同步隊列和異步隊列的說法,其實只是一種形象的稱呼,分別表明主線程中的任務和任務隊列中的任務,那麼此篇咱們就來詳細探討這二者。html

1、來張圖感覺一下html5

若是看完以爲一臉懵逼,請繼續往下看。promise

2、解析異步

咱們仍是拿上篇的例子作解析oop

step1:f一、Promise對象實例化、f2被放入主線程的堆內存中;spa

step2:Promise對象實例化後的同步代碼塊被放入主線程的執行棧中執行,而且產生的異步任務被放入任務隊列;線程

step3:f1被放入主線程的執行棧中執行(打印「我是F1」),for循環產生的1000個定時器(異步任務)放入任務隊列;3d

step4:f2被放入主線程的執行棧中執行,連續5次;code

step5:至此,主線程的執行棧中已經沒有任務了,因而事件循環(event loop)機制從任務隊列中取出一個任務放入主線程的執行棧中執行;server

step6:等待主線程的執行棧中又沒有任務了,事件循環機制再次去任務隊列中取出任務;

step7:重複第6步。

 3、任務隊列

上面提到了任務隊列,任務隊列就是等候執行的一系列任務,就比如鍋裏的飯,你只有把碗裏的飯吃完了,才能再次去鍋裏再盛一碗(不要槓!);

只有主線程的執行棧中沒有了任務,事件循環機制纔會去任務隊列拿任務去執行。

由剛開始的圖,你也看到了,任務隊列是分不一樣類別而且是有優先級的。

  • 任務隊列又分爲macro-task(宏任務)和micro-task(微任務);
  • macro-task大概包括:script(總體代碼),setTimeout,setInterval,setImmediate,I/O,UI rendering;
  • micro-task大概包括:process.nextTick,Promise,Object.observe(已廢棄),MutationObserver(html5新特性)
  • setTimeout/Promise等咱們稱之爲任務源。而進入任務隊列的是他們指定的具體執行任務。
  • 來自不一樣任務源的任務會進入到不一樣的任務隊列

優先級的話,micro-task > macro-task;

對於micro-task:process.nextTick > Promise.then

對於macro-task:setTimeout > setImmediate

具體的案例演示,請參照這篇文章: 事件循環的順序(優先級)
4、簡單demo帶你理解事件循環
Promise.resolve().then(()=>{
  console.log('Promise1')  
  setTimeout(()=>{
    console.log('setTimeout2')
  },0)
})

setTimeout(()=>{
  console.log('setTimeout1')
  Promise.resolve().then(()=>{
    console.log('Promise2')    
  })
},0)

step1:

分析:開始任務隊列裏有微任務promise1和宏任務timeout1,第一次事件循環一看有微任務,二話不說,直接拿promise1到主線程跑(實際上是跑完全部的微任務);promise1運行結果是,控制檯打印promise1,並生成一個宏任務timeout2。

step2:

分析:由於此時任務隊列裏只有宏任務,因而,根據隊列規則以及優先級(這裏只有一種宏任務,因此沒有涉及到優先級),事件循環拿timeout1去主線程跑;

timeout1運行結果,打印setTimeout1,並生成一個微任務promise2,至此第一次事件循環結束。

 

step3:

分析:任務隊列裏有微任務promise2和宏任務timeout2,事件循環一看有微任務,二話不說,直接拿promise2到主線程跑;

運行結果,控制檯打印promise2,此時任務隊列只剩下一個宏任務timeout2。

step4:

分析:此時任務隊列只有一個宏任務timeout2,事件循環二話不說,由於沒得挑了嘛,直接拿到主線程去跑,控制檯打印timeout2,至此結束,也是第二次事件循環結束。

因此,一次事件循環是跑完全部微任務並推一個宏任務到主線程的過程。

相關文章
相關標籤/搜索