nodejs-第二章-第二節-nodejs事件循環(2-1)

當Node.js啓動時會初始化event loop,每一個event loop 都會包含按以下六個節點循環,nodejs事件循環和瀏覽器事件循環徹底不同。

nodejs事件循環

  • 圖中的每一個方框被稱做事件循環的一個"階段",這6個階段爲一輪事件循環;
階段概覽
  • timers(定時器): 此階段執行那些有setTimeout() 和 setInterval()調度的回調函數;
  • I/O callbacks(I/O回調):此階段會執行幾乎全部的回調函數,除了close callbacks(關閉回調) 和 那些有timers與setImmediate()調度的回調;
  • idle(空轉),prepare: 此階段只在內部使用;
  • poll(輪詢): 檢索新的I/O事件;在恰當的時候Node會阻塞在這個節點;
  • check(檢查): setImmediate() 設置的回調會在此階段被調用;
  • close callbacks(關閉事件的回調):
    • 如:socket.on('close',...);此類的回調會在此階段被調用; 在事件循環每次運行之間,Node.js會檢查它是否等待異步I/O或定時器,若是沒有的話就會自動關閉;

若是event loop 進入了poll階段,且代碼未設定timer,將會發生下面的狀況:node

  • 若是poll queue不爲空,event loop將同步的執行queue裏的callback,知道queue爲空,或執行的callback達到系統的上限;
  • 若是poll queue爲空,將會發生下面的狀況:
    • 若是代碼已經被setImmediate()設定了callback,event loop 將結束poll階段進入check階段,並執行check階段的queue(check階段的queue是setImmediate設定的)
    • 若是代碼沒有設定setImmediate(callback),event loop將阻塞在該階段等待callbacks加入poll queue,一旦達到就當即執行;

若是event loop進入了poll階段,且代碼設定了timer:瀏覽器

  • 若是poll queue進入空狀態時(即poll階段爲空閒狀態),event loop將阻塞在該階段等待callbacks加入poll queue,一旦達到就當即執行;

setImmediate約定於setTimeout(cb,0)
  • path.resolve() 方法會把一個路徑或路徑片斷的序列解析爲一個絕對路徑。異步

  • __dirname 老是指向當前文件夾的絕對路徑socket

  • __filename 老是指向當前文件的絕對路徑函數

  • note:oop

    • io: 瀏覽器線程去調用一些異步的回調
  • 執行代碼1
var fs = require('fs');
var path = require('path');
function someAsyncOperation(callback) {
  // 花費2ms
  fs.readFileSync('./read.txt', callback);
}
var timeoutScheduled = Date.now();
var fileReadTime = 0;
setTimeout(function() {
  var delay = Date.now() - timeoutScheduled;
  console.log(`setTimeout ${delay} ms have passed since I was sheculed`);
  console.log('fileReaderTime', fileReadTime - timeoutScheduled);
}, 10);

someAsyncOperation(function() {
  fileReadtime = Date.now();
  while (Date.now() - fileReadTime < 20) {}
});
  • 執行過程:
    • setTimeout和readFile前後加入io
    • setTimeout執行進入io;(須要10ms)
    • readfile執行,也進入io;(須要2ms)
    • 2ms以後, redfile已經讀取完畢,加入poll隊列,此時poll爲空,執行someAsyncOperation回調;
    • 因爲此回調有while,這裏阻塞20ms;執行完爲22ms
    • 在10ms時,setTimeout不能執行,由於js是單線程,setTimeout一直被阻塞
    • 執行完以後(22ms之後),poll 進入空閒狀態
    • event loop檢查timer,setTimeout回調;
  • 執行結果:
    • readFile執行22ms
    • setTimeout執行22ms以後
  • 執行代碼2
var fs = require('fs');
var path = require('path');
function someAsyncOperation(callback) {
  // 花費9ms
  fs.readFileSync('./read.txt', callback);
}
var timeoutScheduled = Date.now();
var fileReadTime = 0;
setTimeout(function() {
  var delay = Date.now() - timeoutScheduled;
  console.log(`setTimeout ${delay} ms have passed since I was sheculed`);
  console.log('fileReaderTime', fileReadTime - timeoutScheduled);
}, 5);

someAsyncOperation(function() {
  fileReadtime = Date.now();
  while (Date.now() - fileReadTime < 20) {}
});
  • 執行結果
    • setTimeout執行:5ms
    • readFile執行9 ~ 29ms
  • 執行代碼3
  • 在nodejs中,setTimeout(fn,0) === setTimeout(fn,0)
  • 在瀏覽器中,setTimeout(fn,0) === setTimeout(fn,4)
setImmediate(() =>{
    console.log('setImmediate')
},0)

setTimeout(() =>{
    console.log('setTimeout')
},0)

// setTimeout 和 setImmediate的執行順序不肯定
// 由於event loop的啓動也是須要時間的,可能執行到poll階段時已經超過了1ms,此時setTimeout會先執行
const fs = require('fs');
const path = require('path');
fs.readFile(path.resolve(__dirname, '/read.txt'), () => {
  setTimeout(() => {
    console.log('setTimeout');
  }, 0);
  setImmediate(() => {
    console.log('setImmediate');
  }, 0);
});
// 執行順序是肯定的, setImmediate,setTimeout
  • 執行過程:
    • 執行fs,第一輪主線程沒有timer和setImmediate
    • 假設readFile須要2ms,執行回調
    • 由poll進入check,setImmediate會先調用
    • 在第二輪的timer階段,會執行setTimeout
相關文章
相關標籤/搜索