帶你了解NodeJS事件循環(huán)
瀏覽器中存在兩個(gè)任務(wù)隊(duì)列,一個(gè)是宏任務(wù)一個(gè)是微任務(wù)。但是在NodeJS中一共存在六個(gè)事件隊(duì)列,timers
,pending callbacks,idle prepare
,poll,check
,close callbacks
。每一個(gè)隊(duì)列里面存放的都是回調(diào)函數(shù)callback
。
這六個(gè)隊(duì)列是按順序執(zhí)行的。每個(gè)隊(duì)列負(fù)責(zé)存儲(chǔ)不同的任務(wù)。
timer
里面存在的是setTimeout與setInterval的回調(diào)函數(shù)pending callback
是執(zhí)行操作系統(tǒng)的回調(diào),例如tcp,udp。idle
和prepare
只在系統(tǒng)內(nèi)部進(jìn)行使用。一般開(kāi)發(fā)者用不到poll
執(zhí)行與IO相關(guān)的回調(diào)操作check
中存放setImmediate中的回調(diào)。close callbacks
執(zhí)行close事件的回調(diào)。
在Node中代碼從上到下同步執(zhí)行,在執(zhí)行過(guò)程中會(huì)將不同的任務(wù)添加到相應(yīng)的隊(duì)列中,比如說(shuō)setTimeout就會(huì)放在timers中, 如果遇到文件讀寫就放在poll里面,等到整個(gè)同步代碼執(zhí)行完畢之后就會(huì)去執(zhí)行滿足條件的微任務(wù)??梢约傧胗幸粋€(gè)隊(duì)列用于存放微任務(wù),這個(gè)隊(duì)列和前面的六種沒(méi)有任何關(guān)系。
當(dāng)同步代碼執(zhí)行完成之后會(huì)去執(zhí)行滿足條件的微任務(wù),一旦所有的微任務(wù)執(zhí)行完畢就會(huì)按照上面列出的順序去執(zhí)行隊(duì)列當(dāng)中滿足條件的宏任務(wù)。
首先會(huì)執(zhí)行timers當(dāng)中滿足條件的宏任務(wù),當(dāng)他將timers中滿足的任務(wù)執(zhí)行完成之后就會(huì)去執(zhí)行隊(duì)列的切換,在切換之前會(huì)先去清空微任務(wù)列表中的微任務(wù)。
所以微任務(wù)執(zhí)行是有兩個(gè)時(shí)機(jī)的,第一個(gè)時(shí)機(jī)是所有的同步代碼執(zhí)行完畢,第二個(gè)時(shí)機(jī)隊(duì)列切換前。
注意在微任務(wù)中nextTick的執(zhí)行優(yōu)先級(jí)要高于Promise
,這個(gè)只能死記了。
setTimeout(() => { ? ? console.log('s1'); }) Promise.resolve().then(() => { ? ? console.log('p1'); }) console.log('start'); process.nextTick(() => { ? ? console.log('tick'); }) setImmediate(() => { ? ? console.log('st'); }) console.log('end'); // start end tick p1 s1 st
setTimeout(() => { ? ? console.log('s1'); ? ? Promise.resolve().then(() => { ? ? ? ? console.log('p1'); ? ? }) ? ? process.nextTick(() => { ? ? ? ? console.log('t1'); ? ? }) }) Promise.resolve().then(() => { ? ? console.log('p2') }) console.log('start'); setTimeout(() => { ? ? console.log('s2'); ? ? Promise.resolve().then(() => { ? ? ? ? console.log('p3'); ? ? }) ? ? process.nextTick(() => { ? ? ? ? console.log('t2'); ? ? }) }) console.log('end'); // start end p2 s1 s2 t1 t2 p1 p3
Node
與瀏覽器事件環(huán)執(zhí)行是有一些不同的。
首先任務(wù)隊(duì)列數(shù)不同,瀏覽器一般只有宏任務(wù)和微任務(wù)兩個(gè)隊(duì)列,而Node中除了微任務(wù)隊(duì)列外還有6個(gè)事件隊(duì)列。
其次微任務(wù)執(zhí)行時(shí)機(jī)不同,不過(guò)他們也有相同的地方就是在同步任務(wù)執(zhí)行完畢之后都會(huì)去看一下微任務(wù)是否存在可執(zhí)行的。對(duì)瀏覽器來(lái)說(shuō)每當(dāng)一個(gè)宏任務(wù)執(zhí)行完成之后就會(huì)清空一次微任務(wù)隊(duì)列。在Node中只有在事件隊(duì)列切換時(shí)才會(huì)去清空微任務(wù)隊(duì)列。
最后在Node平臺(tái)下微任務(wù)執(zhí)行是有優(yōu)先級(jí)的,nextTick優(yōu)先于Promise.then
, 而瀏覽器中則是先進(jìn)先出。
setTimeout(() => { ? ? console.log('timeout'); }) setImmediate(() => { ? ? console.log('immdieate'); })
在Node中時(shí)而會(huì)先輸出timeout
時(shí)而會(huì)先輸出immdieate
,這是因?yàn)?code>setTimeout是需要接收一個(gè)時(shí)間參數(shù)的,如果沒(méi)寫就是一個(gè)0,我們都知道無(wú)論是在Node還是在瀏覽器,程序是不可能真的是0,他會(huì)受很多的因素影響。這取決于運(yùn)行的環(huán)境。
如果setTimeout先執(zhí)行就會(huì)放在timers隊(duì)列中,這樣timeout就會(huì)先輸入,如果setTimeout因?yàn)槟承┰蚝髨?zhí)行了,那么check隊(duì)列中的immdieate
就會(huì)先執(zhí)行。這就是為什么時(shí)而輸出timeout時(shí)而輸出immdieate
。
const fs = require('fs'); fs.readFile('./a.txt', () => { ? ? setTimeout(() => { ? ? ? ? console.log('timeout'); ? ? }, 0) ? ? setImmediate(() => { ? ? ? ? console.log('immdieate'); ? ? }) })
這種情況就會(huì)一直先輸出immdieate
后輸出timeout
,這是因?yàn)椋a執(zhí)行的時(shí)候會(huì)在timers里面加入timeout, 在poll中加入fs的回調(diào),在check中加入immdieate
。fs的回調(diào)執(zhí)行結(jié)束之后實(shí)在poll隊(duì)列,隊(duì)列切換的時(shí)候首先會(huì)去看微任務(wù),但是這里沒(méi)有微任務(wù)就會(huì)繼續(xù)向下,下面就是check隊(duì)列而不是timers隊(duì)列,所以poll清空之后會(huì)切換到check隊(duì)列,執(zhí)行immdieate回調(diào)。
到此這篇關(guān)于帶你了解NodeJS事件循環(huán)的文章就介紹到這了,更多相關(guān)NodeJS事件循環(huán)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- nodeJs事件循環(huán)運(yùn)行代碼解析
- Nodejs監(jiān)控事件循環(huán)異常示例詳解
- 詳解nodejs異步I/O和事件循環(huán)
- 我的Node.js學(xué)習(xí)之路(三)--node.js作用、回調(diào)、同步和異步代碼 以及事件循環(huán)
- Node.js事件循環(huán)(Event Loop)和線程池詳解
- 深入理解Node.js 事件循環(huán)和回調(diào)函數(shù)
- 小結(jié)Node.js中非阻塞IO和事件循環(huán)
- 深入淺析Node.js 事件循環(huán)
- 實(shí)例分析JS與Node.js中的事件循環(huán)
- nodejs?快速入門之事件循環(huán)
相關(guān)文章
在Linux系統(tǒng)上更新Node.js到最新版本的3種方法小結(jié)
這篇文章主要介紹了在Linux系統(tǒng)上更新Node.js到最新版本的3種方法,使用NVM,使用NPM,用二進(jìn)制包更新Node.js,文中有詳解更新方法,需要的朋友可以參考下2023-09-09node.js中的fs.unlink方法使用說(shuō)明
這篇文章主要介紹了node.js中的fs.unlink方法使用說(shuō)明,本文介紹了fs.unlink的方法說(shuō)明、語(yǔ)法、接收參數(shù)、使用實(shí)例和實(shí)現(xiàn)源碼,需要的朋友可以參考下2014-12-12Node.js 使用流實(shí)現(xiàn)讀寫同步邊讀邊寫功能
本文通過(guò)代碼給大家介紹了Node.js 使用流實(shí)現(xiàn)讀寫同步邊讀邊寫功能,非常不錯(cuò),具有參考借鑒價(jià)值,需要的額朋友參考下吧2017-09-09node.js中的buffer.toJSON方法使用說(shuō)明
這篇文章主要介紹了node.js中的buffer.toJSON方法使用說(shuō)明,本文介紹了buffer.toJSON的方法說(shuō)明、語(yǔ)法、接收參數(shù)、使用實(shí)例和實(shí)現(xiàn)源碼,需要的朋友可以參考下2014-12-12Node.js中常用設(shè)計(jì)模式的使用方法總結(jié)
設(shè)計(jì)模式是由經(jīng)驗(yàn)豐富的程序員在日積月累中抽象出的用以解決通用問(wèn)題的可復(fù)用解決方案,它提供了標(biāo)準(zhǔn)化的代碼設(shè)計(jì)方案提升開(kāi)發(fā)體驗(yàn),本文主要來(lái)和大家討論一下Node.js中設(shè)計(jì)模式的重要性并提供一些代碼示例,感興趣的可以了解下2023-10-10Node.js操作Firebird數(shù)據(jù)庫(kù)教程
這篇文章主要為大家分享了Node.js操作Firebird數(shù)據(jù)庫(kù)教程,思路清晰便于大家理解,感興趣的小伙伴們可以參考一下2016-03-03Node.js中的HTTP請(qǐng)求與響應(yīng)詳解
本文詳細(xì)講解了Node.js中的HTTP請(qǐng)求與響應(yīng),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07