您好,登錄后才能下訂單哦!
nodejs中怎么實(shí)現(xiàn)事件循環(huán),針對這個(gè)問題,這篇文章詳細(xì)介紹了相對應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問題的小伙伴找到更簡單易行的方法。
圖中的每個(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)知識。
免責(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)容。