自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

面試官:說說對 Node.js 中的事件循環(huán)機制理解?

開發(fā) 前端
在瀏覽器事件循環(huán)中,我們了解到j(luò)avascript在瀏覽器中的事件循環(huán)機制,其是根據(jù)HTML5定義的規(guī)范來實現(xiàn)

本文轉(zhuǎn)載自微信公眾號「JS每日一題」,作者灰灰。轉(zhuǎn)載本文請聯(lián)系JS每日一題公眾號。  

一、是什么

在瀏覽器事件循環(huán)中,我們了解到j(luò)avascript在瀏覽器中的事件循環(huán)機制,其是根據(jù)HTML5定義的規(guī)范來實現(xiàn)

而在NodeJS中,事件循環(huán)是基于libuv實現(xiàn),libuv是一個多平臺的專注于異步IO的庫,如下圖最右側(cè)所示:

上圖EVENT_QUEUE 給人看起來只有一個隊列,但EventLoop存在6個階段,每個階段都有對應(yīng)的一個先進先出的回調(diào)隊列

二、流程

上節(jié)講到事件循環(huán)分成了六個階段,對應(yīng)如下:

  • timers階段:這個階段執(zhí)行timer(setTimeout、setInterval)的回調(diào)
  • 定時器檢測階段(timers):本階段執(zhí)行 timer 的回調(diào),即 setTimeout、setInterval 里面的回調(diào)函數(shù)
  • I/O事件回調(diào)階段(I/O callbacks):執(zhí)行延遲到下一個循環(huán)迭代的 I/O 回調(diào),即上一輪循環(huán)中未被執(zhí)行的一些I/O回調(diào)
  • 閑置階段(idle, prepare):僅系統(tǒng)內(nèi)部使用
  • 輪詢階段(poll):檢索新的 I/O 事件;執(zhí)行與 I/O 相關(guān)的回調(diào)(幾乎所有情況下,除了關(guān)閉的回調(diào)函數(shù),那些由計時器和 setImmediate() 調(diào)度的之外),其余情況 node 將在適當(dāng)?shù)臅r候在此阻塞
  • 檢查階段(check):setImmediate() 回調(diào)函數(shù)在這里執(zhí)行
  • 關(guān)閉事件回調(diào)階段(close callback):一些關(guān)閉的回調(diào)函數(shù),如:socket.on('close', ...)

每個階段對應(yīng)一個隊列,當(dāng)事件循環(huán)進入某個階段時, 將會在該階段內(nèi)執(zhí)行回調(diào),直到隊列耗盡或者回調(diào)的最大數(shù)量已執(zhí)行, 那么將進入下一個處理階段

除了上述6個階段,還存在process.nextTick,其不屬于事件循環(huán)的任何一個階段,它屬于該階段與下階段之間的過渡, 即本階段執(zhí)行結(jié)束, 進入下一個階段前, 所要執(zhí)行的回調(diào),類似插隊

流程圖如下所示:

在Node中,同樣存在宏任務(wù)和微任務(wù),與瀏覽器中的事件循環(huán)相似

微任務(wù)對應(yīng)有:

  • next tick queue:process.nextTick
  • other queue:Promise的then回調(diào)、queueMicrotask

宏任務(wù)對應(yīng)有:

  • timer queue:setTimeout、setInterval
  • poll queue:IO事件
  • check queue:setImmediate
  • close queue:close事件

其執(zhí)行順序為:

  • next tick microtask queue
  • other microtask queue
  • timer queue
  • poll queue
  • check queue
  • close queue

三、題目

通過上面的學(xué)習(xí),下面開始看看題目

  1. async function async1() { 
  2.     console.log('async1 start'
  3.     await async2() 
  4.     console.log('async1 end'
  5.  
  6. async function async2() { 
  7.     console.log('async2'
  8.  
  9. console.log('script start'
  10.  
  11. setTimeout(function () { 
  12.     console.log('setTimeout0'
  13. }, 0) 
  14.  
  15. setTimeout(function () { 
  16.     console.log('setTimeout2'
  17. }, 300) 
  18.  
  19. setImmediate(() => console.log('setImmediate')); 
  20.  
  21. process.nextTick(() => console.log('nextTick1')); 
  22.  
  23. async1(); 
  24.  
  25. process.nextTick(() => console.log('nextTick2')); 
  26.  
  27. new Promise(function (resolve) { 
  28.     console.log('promise1'
  29.     resolve(); 
  30.     console.log('promise2'
  31. }).then(function () { 
  32.     console.log('promise3'
  33. }) 
  34.  
  35. console.log('script end'

分析過程:

  • 先找到同步任務(wù),輸出script start
  • 遇到第一個 setTimeout,將里面的回調(diào)函數(shù)放到 timer 隊列中
  • 遇到第二個 setTimeout,300ms后將里面的回調(diào)函數(shù)放到 timer 隊列中
  • 遇到第一個setImmediate,將里面的回調(diào)函數(shù)放到 check 隊列中
  • 遇到第一個 nextTick,將其里面的回調(diào)函數(shù)放到本輪同步任務(wù)執(zhí)行完畢后執(zhí)行
  • 執(zhí)行 async1函數(shù),輸出 async1 start
  • 執(zhí)行 async2 函數(shù),輸出 async2,async2 后面的輸出 async1 end進入微任務(wù),等待下一輪的事件循環(huán)
  • 遇到第二個,將其里面的回調(diào)函數(shù)放到本輪同步任務(wù)執(zhí)行完畢后執(zhí)行
  • 遇到 new Promise,執(zhí)行里面的立即執(zhí)行函數(shù),輸出 promise1、promise2
  • then里面的回調(diào)函數(shù)進入微任務(wù)隊列
  • 遇到同步任務(wù),輸出 script end
  • 執(zhí)行下一輪回到函數(shù),先依次輸出 nextTick 的函數(shù),分別是 nextTick1、nextTick2
  • 然后執(zhí)行微任務(wù)隊列,依次輸出 async1 end、promise3
  • 執(zhí)行timer 隊列,依次輸出 setTimeout0
  • 接著執(zhí)行 check 隊列,依次輸出 setImmediate
  • 300ms后,timer 隊列存在任務(wù),執(zhí)行輸出 setTimeout2

執(zhí)行結(jié)果如下:

  1. script start 
  2. async1 start 
  3. async2 
  4. promise1 
  5. promise2 
  6. script end 
  7. nextTick1 
  8. nextTick2 
  9. async1 end 
  10. promise3 
  11. setTimeout0 
  12. setImmediate 
  13. setTimeout2 

最后有一道是關(guān)于setTimeout與setImmediate的輸出順序

  1. setTimeout(() => { 
  2.   console.log("setTimeout"); 
  3. }, 0); 
  4.  
  5. setImmediate(() => { 
  6.   console.log("setImmediate"); 
  7. }); 

輸出情況如下:

  1. 情況一: 
  2. setTimeout 
  3. setImmediate 
  4.  
  5. 情況二: 
  6. setImmediate 
  7. setTimeout 

分析下流程:

  • 外層同步代碼一次性全部執(zhí)行完,遇到異步API就塞到對應(yīng)的階段
  • 遇到setTimeout,雖然設(shè)置的是0毫秒觸發(fā),但實際上會被強制改成1ms,時間到了然后塞入times階段
  • 遇到setImmediate塞入check階段
  • 同步代碼執(zhí)行完畢,進入Event Loop
  • 先進入times階段,檢查當(dāng)前時間過去了1毫秒沒有,如果過了1毫秒,滿足setTimeout條件,執(zhí)行回調(diào),如果沒過1毫秒,跳過
  • 跳過空的階段,進入check階段,執(zhí)行setImmediate回調(diào)
  • 這里的關(guān)鍵在于這1ms,如果同步代碼執(zhí)行時間較長,進入Event Loop的時候1毫秒已經(jīng)過了,setTimeout先執(zhí)行,如果1毫秒還沒到,就先執(zhí)行了setImmediate

參考文獻

https://segmentfault.com/a/1190000012258592

https://juejin.cn/post/6844904100195205133

 

https://vue3js.cn/interview/

 

責(zé)任編輯:武曉燕 來源: JS每日一題
相關(guān)推薦

2021-06-30 07:19:36

React事件機制

2021-06-07 09:41:48

NodeBuffer 網(wǎng)絡(luò)協(xié)議

2021-06-08 08:33:23

NodeStream數(shù)據(jù)

2021-06-03 08:14:01

NodeProcessJavaScript

2024-01-05 08:49:15

Node.js異步編程

2021-06-04 07:55:30

Node Fs 操作

2021-05-31 10:35:34

TCPWebSocket協(xié)議

2021-06-01 08:25:06

Node.jsJavaScript運行

2021-07-12 08:35:24

組件應(yīng)用場景

2021-05-27 09:00:00

Node.js開發(fā)線程

2021-07-07 08:36:45

React應(yīng)用場景

2021-09-13 09:23:52

TypeScript命名空間

2021-06-15 10:01:02

應(yīng)用系統(tǒng)軟件

2024-08-26 14:52:58

JavaScript循環(huán)機制

2021-07-13 07:52:03

ReactHooks組件

2017-08-16 10:36:10

JavaScriptNode.js事件驅(qū)動

2021-10-29 09:40:21

設(shè)計模式軟件

2021-07-29 07:55:20

React Fiber架構(gòu)引擎

2021-06-29 09:47:34

ReactSetState機制

2021-06-02 09:42:29

Node. js全局對象
點贊
收藏

51CTO技術(shù)棧公眾號