nodejs中怎么實現(xiàn)事件循環(huán),針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
成都創(chuàng)新互聯(lián)公司長期為上千家客戶提供的網(wǎng)站建設服務,團隊從業(yè)經(jīng)驗10年,關(guān)注不同地域、不同群體,并針對不同對象提供差異化的產(chǎn)品和服務;打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為安塞企業(yè)提供專業(yè)的成都網(wǎng)站制作、網(wǎng)站設計,安塞網(wǎng)站改版等技術(shù)服務。擁有十多年豐富建站經(jīng)驗和眾多成功案例,為您定制開發(fā)。
圖中的每個方框被稱作事件循環(huán)的一個"階段",這6個階段為一輪事件循環(huán);
timers(定時器): 此階段執(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事件;在恰當?shù)臅r候Node會阻塞在這個節(jié)點;
check(檢查): setImmediate() 設置的回調(diào)會在此階段被調(diào)用;
close callbacks(關(guān)閉事件的回調(diào)):
如:socket.on('close',...);此類的回調(diào)會在此階段被調(diào)用; 在事件循環(huán)每次運行之間,Node.js會檢查它是否等待異步I/O或定時器,如果沒有的話就會自動關(guān)閉;
如果event loop 進入了poll階段,且代碼未設定timer,將會發(fā)生下面的情況:
如果poll queue不為空,event loop將同步的執(zhí)行queue里的callback,知道queue為空,或執(zhí)行的callback達到系統(tǒng)的上限;
如果poll queue為空,將會發(fā)生下面的情況:
如果代碼已經(jīng)被setImmediate()設定了callback,event loop 將結(jié)束poll階段進入check階段,并執(zhí)行check階段的queue(check階段的queue是setImmediate設定的)
如果代碼沒有設定setImmediate(callback),event loop將阻塞在該階段等待callbacks加入poll queue,一旦達到就立即執(zhí)行;
如果event loop進入了poll階段,且代碼設定了timer:
如果poll queue進入空狀態(tài)時(即poll階段為空閑狀態(tài)),event loop將阻塞在該階段等待callbacks加入poll queue,一旦達到就立即執(zhí)行;
setImmediate約定于setTimeout(cb,0)
path.resolve() 方法會把一個路徑或路徑片段的序列解析為一個絕對路徑。
__dirname 總是指向當前文件夾的絕對路徑
__filename 總是指向當前文件的絕對路徑
note:
io: 瀏覽器線程去調(diào)用一些異步的回調(diào)
執(zhí)行代碼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) {} });
執(zhí)行過程:
setTimeout和readFile先后加入io
setTimeout執(zhí)行進入io;(需要10ms)
readfile執(zhí)行,也進入io;(需要2ms)
2ms之后, redfile已經(jīng)讀取完畢,加入poll隊列,此時poll為空,執(zhí)行someAsyncOperation回調(diào);
由于此回調(diào)有while,這里阻塞20ms;執(zhí)行完為22ms
在10ms時,setTimeout不能執(zhí)行,因為js是單線程,setTimeout一直被阻塞
執(zhí)行完之后(22ms以后),poll 進入空閑狀態(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) { // 花費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í)行順序不確定 // 因為event loop的啟動也是需要時間的,可能執(zhí)行到poll階段時已經(jīng)超過了1ms,此時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
假設readFile需要2ms,執(zhí)行回調(diào)
由poll進入check,setImmediate會先調(diào)用
在第二輪的timer階段,會執(zhí)行setTimeout
關(guān)于nodejs中怎么實現(xiàn)事件循環(huán)問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關(guān)知識。