溫馨提示×

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

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

NodeJS事件循環(huán)實(shí)例分析

發(fā)布時(shí)間:2022-02-14 13:39:10 來(lái)源:億速云 閱讀:109 作者:iii 欄目:開(kāi)發(fā)技術(shù)

這篇文章主要介紹“NodeJS事件循環(huán)實(shí)例分析”,在日常操作中,相信很多人在NodeJS事件循環(huán)實(shí)例分析問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”NodeJS事件循環(huán)實(shí)例分析”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

NodeJS事件循環(huán)實(shí)例分析

瀏覽器中存在兩個(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中, 如果遇到文件讀寫(xiě)就放在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)寫(xiě)就是一個(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)?,代碼執(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)實(shí)例分析”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

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

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

AI