瀏覽器/nodeJS中的EventLoop

大家都知道JS是一門單線程語言,也就意味著JS無法進行多線程,但是JS中異步的概念完全可以模擬多線程,而且效果差不到哪去

要完全理解異步,就需要了解 JS 的運行核心——事件循環(huán)(event loop)

但是在瀏覽器中運行JS和在nodeJS中運行還有一些差別,接下來我們就來看看這些差別在哪里

首先是瀏覽器中的EventLoop
在說瀏覽器EventLoop之前我們要先看看瀏覽器模型

瀏覽器模型.png
  • 用戶界面 包括地址欄,書簽欄等那些東西
  • 瀏覽器引擎 在用戶界面,呈現(xiàn)引擎之間傳送指令
  • 渲染引擎 也被稱為呈現(xiàn)引擎
  • 請求(網(wǎng)絡(luò)) 用于網(wǎng)絡(luò)調(diào)用,比如HTTP請求
  • JS解釋器 用于解析和執(zhí)行JS代碼
  • UI(用戶界面后端) 用于繪制樣式 和JS共用一個線程
  • 數(shù)據(jù)存儲 瀏覽器需要保存的一些數(shù)據(jù) 不如Cookie

JS和css公用一個線程是因為瀏覽器不會同時渲染JS和css,一般都會先渲染css再執(zhí)行JS

瀏覽器中的微任務(wù)
??then
??messageChannel
??mutationObersve

瀏覽器中的宏任務(wù)
??setTimeout
??setInterval

代碼調(diào)用先進堆棧,堆棧是代碼的總執(zhí)行站,堆棧整個執(zhí)行的過程中會先將微任務(wù),宏任務(wù)放到相應(yīng)的隊列中,事件提出來等待觸發(fā),等到總執(zhí)行站中的代碼空了,會先看微任務(wù)隊列中有沒有,如果有就會放到總執(zhí)行站中執(zhí)行,然后在看宏任務(wù)隊列中有沒有。

瀏覽器EventLoop.png
setTimeout(function () {
    console.log('setTimeout')
})
Promise.resolve().then(function () {
      console.log('promise')
});
console.log('堆棧');

// 執(zhí)行結(jié)果:
// 堆棧
// promise
// setTimeout

如果把微任務(wù)隊列放到堆棧中執(zhí)行的時候又發(fā)現(xiàn)了宏任務(wù),會順便吧微任務(wù)中的宏任務(wù)一起執(zhí)行了

setTimeout(function () {
    console.log('setTimeout1')
    Promise.resolve().then(function () {
        console.log('promise')
    });
})
setTimeout(function () {
    console.log('setTimeout2');
});

// 執(zhí)行結(jié)果:
// setTimeout1
// promise
// setTimeout2

然后是nodeJS運行環(huán)境中的EventLoop
nodeJS中的宏任務(wù)和微任務(wù)在瀏覽器的基礎(chǔ)上有新增了幾個
微任務(wù)
??then
??nextTick
??messageChannel
??mutationObersve

宏任務(wù)
??setTimeout
??setInterval
??setImmediate、

node的調(diào)用順序中會比瀏覽器中的復(fù)雜一些

nodeJS EventLoop.png

看圖雖然復(fù)雜,但是我們只需要關(guān)心timers計時器階段,poll輪詢階段,check檢查階段(setImmediate回掉),clons關(guān)閉階段以及微任務(wù)隊列即可,因為處理網(wǎng)絡(luò),內(nèi)部調(diào)用與咱們的宏任務(wù)和微任務(wù)的執(zhí)行沒有太大的關(guān)系
和瀏覽器運行環(huán)境不同的是微任務(wù)只會在階段轉(zhuǎn)化的時候才會調(diào)用,就是close關(guān)閉階段后再執(zhí)行下一階段的時候

process.nextTick(function () {
    console.log('nextTick')
});
setImmediate(function () {
    console.log('setImmediate')
});

// 執(zhí)行結(jié)果:
// nextTick
// setImmediate

如果宏任務(wù)執(zhí)行的時候又發(fā)現(xiàn)微任務(wù)了,不會和瀏覽器一樣順便執(zhí)行了,而是會將微任務(wù)再放到微任務(wù)隊列中,等待整個階段結(jié)束后,下一個階段開始的時候先執(zhí)行完微任務(wù)隊列中的微任務(wù)

setTimeout(function () {
    console.log('setTimeout1')
    Promise.resolve().then(function () {
        console.log('promise')
    });
})
setTimeout(function () {
    console.log('setTimeout2');
});

// 執(zhí)行結(jié)果:
// setTimeout1
// promise
// setTimeout2

反之亦然

process.nextTick(function () {
    console.log(1)
    setImmediate(function () {
        console.log(2);
    })
})
setImmediate(function () {
    console.log(3);
    process.nextTick(function () {
        console.log(4)
    })
})

// 執(zhí)行結(jié)果:
// 1
// 3
// 2
// 4

timeout immediate 兩個誰先執(zhí)行不一定 取決于node的執(zhí)行時間

setTimeout(function () {
    console.log('setTimeout');
})
setImmediate(function () {
    console.log('setImmediate')
});

// 執(zhí)行結(jié)果:
// setTimeout
// setImmediate
// 或者:
// setImmediate
// setTimeout

但是加上i/o文件操作以后就會先執(zhí)行setImmediate,因為setImmediate在i/o文件操作后面的那個階段執(zhí)行,執(zhí)行完setImmediate會在下一個階段的時候再執(zhí)行setTimeout (timers 計時器執(zhí)行階段)

let fs = require('fs');
fs.readFile('./1.txt', function () {
    console.log('fs');
    setTimeout(function () {
        console.log('setTimeout');
    })
    setImmediate(function () {
        console.log('setImmediate')
    })
});

// 執(zhí)行結(jié)果
// fs
// setImmediate
// setTimeout
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 蔡麗萍祝大家新年快樂!狗年發(fā)大財;幸福安康;心想事成;萬事如意;洪福齊天;風(fēng)光無限;笑口常開;好運連連;財源滾滾;...
    小草麗人閱讀 610評論 0 0
  • 1. 捧著半兒拉西瓜挖著吃的時候 2. 躺在床上上無憂無慮發(fā)呆的時候 3. 上完一天班后躺在床上看電影,并拿著半兒...
    馬雨_Val閱讀 193評論 0 1
  • PHP是一門對新手友好的編程語言,規(guī)矩很少,內(nèi)置函數(shù)和可擴展模塊很多。最重要的是PHP官方手冊十分詳細而且有中文版...
    yxtm閱讀 362評論 0 0
  • 云映日而成霞,泉掛巖而成瀑。所托者異,而名亦因之。此友道之所以可貴也。 如《顏氏家訓(xùn)》說:與善人居,如入芝蘭之室,...
    轉(zhuǎn)彎彎閱讀 295評論 0 0

友情鏈接更多精彩內(nèi)容