溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

nodejs中怎么實(shí)現(xiàn)事件循環(huán)

發(fā)布時(shí)間:2021-06-22 15:08:33 來源:億速云 閱讀:259 作者:Leah 欄目:大數(shù)據(jù)

nodejs中怎么實(shí)現(xiàn)事件循環(huán),針對這個(gè)問題,這篇文章詳細(xì)介紹了相對應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問題的小伙伴找到更簡單易行的方法。

當(dāng)Node.js啟動(dòng)時(shí)會初始化event loop,每個(gè)event loop 都會包含按如下六個(gè)節(jié)點(diǎn)循環(huán),nodejs事件循環(huán)和瀏覽器事件循環(huán)完全不一樣。

nodejs中怎么實(shí)現(xiàn)事件循環(huán)

  • 圖中的每個(gè)方框被稱作事件循環(huán)的一個(gè)"階段",這6個(gè)階段為一輪事件循環(huán);

階段概覽
  • timers(定時(shí)器): 此階段執(zhí)行那些有setTimeout() 和 setInterval()調(diào)度的回調(diào)函數(shù);

  • I/O callbacks(I/O回調(diào)):此階段會執(zhí)行幾乎所有的回調(diào)函數(shù),除了close callbacks(關(guān)閉回調(diào)) 和 那些有timers與setImmediate()調(diào)度的回調(diào);

  • idle(空轉(zhuǎn)),prepare: 此階段只在內(nèi)部使用;

  • poll(輪詢): 檢索新的I/O事件;在恰當(dāng)?shù)臅r(shí)候Node會阻塞在這個(gè)節(jié)點(diǎn);

  • check(檢查): setImmediate() 設(shè)置的回調(diào)會在此階段被調(diào)用;

  • close callbacks(關(guān)閉事件的回調(diào)):

    • 如:socket.on('close',...);此類的回調(diào)會在此階段被調(diào)用; 在事件循環(huán)每次運(yùn)行之間,Node.js會檢查它是否等待異步I/O或定時(shí)器,如果沒有的話就會自動(dòng)關(guān)閉;


如果event loop 進(jìn)入了poll階段,且代碼未設(shè)定timer,將會發(fā)生下面的情況:

  • 如果poll queue不為空,event loop將同步的執(zhí)行queue里的callback,知道queue為空,或執(zhí)行的callback達(dá)到系統(tǒng)的上限;

  • 如果poll queue為空,將會發(fā)生下面的情況:

    • 如果代碼已經(jīng)被setImmediate()設(shè)定了callback,event loop 將結(jié)束poll階段進(jìn)入check階段,并執(zhí)行check階段的queue(check階段的queue是setImmediate設(shè)定的)

    • 如果代碼沒有設(shè)定setImmediate(callback),event loop將阻塞在該階段等待callbacks加入poll queue,一旦達(dá)到就立即執(zhí)行;

如果event loop進(jìn)入了poll階段,且代碼設(shè)定了timer:

  • 如果poll queue進(jìn)入空狀態(tài)時(shí)(即poll階段為空閑狀態(tài)),event loop將阻塞在該階段等待callbacks加入poll queue,一旦達(dá)到就立即執(zhí)行;


setImmediate約定于setTimeout(cb,0)
  • path.resolve() 方法會把一個(gè)路徑或路徑片段的序列解析為一個(gè)絕對路徑。

  • __dirname 總是指向當(dāng)前文件夾的絕對路徑

  • __filename 總是指向當(dāng)前文件的絕對路徑

  • note:

    • io: 瀏覽器線程去調(diào)用一些異步的回調(diào)

  • 執(zhí)行代碼1

var fs = require('fs');
var path = require('path');
function someAsyncOperation(callback) {
  // 花費(fèi)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) {}
});
  • 執(zhí)行過程:

    • setTimeout和readFile先后加入io

    • setTimeout執(zhí)行進(jìn)入io;(需要10ms)

    • readfile執(zhí)行,也進(jìn)入io;(需要2ms)

    • 2ms之后, redfile已經(jīng)讀取完畢,加入poll隊(duì)列,此時(shí)poll為空,執(zhí)行someAsyncOperation回調(diào);

    • 由于此回調(diào)有while,這里阻塞20ms;執(zhí)行完為22ms

    • 在10ms時(shí),setTimeout不能執(zhí)行,因?yàn)閖s是單線程,setTimeout一直被阻塞

    • 執(zhí)行完之后(22ms以后),poll 進(jìn)入空閑狀態(tài)

    • event loop檢查timer,setTimeout回調(diào);

  • 執(zhí)行結(jié)果:

    • readFile執(zhí)行22ms

    • setTimeout執(zhí)行22ms之后

  • 執(zhí)行代碼2

var fs = require('fs');
var path = require('path');
function someAsyncOperation(callback) {
  // 花費(fèi)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) {}
});
  • 執(zhí)行結(jié)果

    • setTimeout執(zhí)行:5ms

    • readFile執(zhí)行9 ~ 29ms

  • 執(zhí)行代碼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的執(zhí)行順序不確定
// 因?yàn)閑vent loop的啟動(dòng)也是需要時(shí)間的,可能執(zhí)行到poll階段時(shí)已經(jīng)超過了1ms,此時(shí)setTimeout會先執(zhí)行
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);
});
// 執(zhí)行順序是確定的, setImmediate,setTimeout
  • 執(zhí)行過程:

    • 執(zhí)行fs,第一輪主線程沒有timer和setImmediate

    • 假設(shè)readFile需要2ms,執(zhí)行回調(diào)

    • 由poll進(jìn)入check,setImmediate會先調(diào)用

    • 在第二輪的timer階段,會執(zhí)行setTimeout

關(guān)于nodejs中怎么實(shí)現(xiàn)事件循環(huán)問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI