瀏覽器事件循環(huán)機(jī)制

沒(méi)有異步機(jī)制會(huì)怎樣

js是單線程的,如果沒(méi)有異步機(jī)制,所有代碼會(huì)同步執(zhí)行。一些比較耗時(shí)的操作比如網(wǎng)絡(luò)請(qǐng)求,會(huì)阻塞線程直到請(qǐng)求返回結(jié)果才會(huì)繼續(xù)向下執(zhí)行。如果這樣js的執(zhí)行效率會(huì)比較低,甚至導(dǎo)致頁(yè)面卡死。所以必須加入異步機(jī)制以提升js線程執(zhí)行效率。

怎么加入異步機(jī)制

單線程和異步是互斥的,所以js線程本身是沒(méi)有異步能力的。但是瀏覽器賦予了js線程異步能力,瀏覽器不僅支持js主線程,還可以開(kāi)辟出http請(qǐng)求線程、定時(shí)器觸發(fā)線程、事件觸發(fā)線程等多種幕后線程。js線程遇到http請(qǐng)求、定時(shí)器等任務(wù),會(huì)把它們交給相應(yīng)的幕后線程執(zhí)行,js線程繼續(xù)向下執(zhí)行,http請(qǐng)求、定時(shí)器等任務(wù)完成后再把回調(diào)放入js隊(duì)列中等待js線程調(diào)用。這樣js線程就具備了異步的能力了。同時(shí)JS引入了Promise使單線程也具備了異步能力。

怎么調(diào)度隊(duì)列中的任務(wù)

瀏覽器把任務(wù)分為兩類(lèi):宏任務(wù)和微任務(wù)。js引擎線程發(fā)起的任務(wù)稱為微任務(wù),瀏覽器其它線程發(fā)起的任務(wù)稱為宏任務(wù)。整體代碼script會(huì)放到宏任務(wù)里;幕后線程執(zhí)行的任務(wù)完成后會(huì)把對(duì)應(yīng)的回調(diào)放到宏任務(wù)里;js主線程會(huì)把某些任務(wù)放到微任務(wù)里,比如:Promise.resolve().then(callback) js主線程會(huì)把callback放到微任務(wù)里。

js線程的一般調(diào)度策略是:js線程從宏任務(wù)中選取一個(gè)任務(wù)執(zhí)行,執(zhí)行完成后,逐個(gè)執(zhí)行微任務(wù)中的任務(wù)直至微任務(wù)為空,然后再次從宏任務(wù)中選取一個(gè)任務(wù)執(zhí)行,如此反復(fù)。js線程從宏任務(wù)中選取一個(gè)任務(wù)開(kāi)始到執(zhí)行完所有微任務(wù)為止稱為一個(gè)事件循環(huán)。比如宏任務(wù)中有兩個(gè)任務(wù)macro1, macro2,微任務(wù)中有三個(gè)任務(wù)micro1, micro2, micro3,那么調(diào)度順序?yàn)椋簃acro1 > micro1 > micro2 > micro3 > macro2。

分析一個(gè)例子:

setTimeout(function timout_1() {
  console.log("timout_1");
}, 0);

Promise.resolve().then(function then_1() {
  console.log("then_1");
});

Promise.resolve().then(function then_2() {
  console.log("then_2");
});

js線程執(zhí)行前,宏任務(wù)里只有整體代碼script,微任務(wù)里沒(méi)有任務(wù)。按照一般調(diào)度策略:

  1. js線程首先從宏任務(wù)里選取整體代碼script執(zhí)行;
  2. 把setTimeout任務(wù)交給計(jì)時(shí)器線程,計(jì)時(shí)器線程會(huì)立刻往宏任務(wù)里加入一個(gè)tiemtimeou_1任務(wù) ;
  3. js線程把then_1加入微任務(wù);
  4. js線程把then_2加入微任務(wù) ;
  5. 執(zhí)行完宏任務(wù)里的整體代碼script,接著要依此執(zhí)行微任務(wù)里的任務(wù),現(xiàn)在微任務(wù)里有then_1和then_2,js線程從微任務(wù)里選取then_1執(zhí)行,控制臺(tái)打印then_1;
  6. js線程從微任務(wù)里選取then_2執(zhí)行,控制臺(tái)打印then_2;
  7. 微任務(wù)里沒(méi)有其它任務(wù),所以第一次事件循環(huán)結(jié)束;
  8. js線程開(kāi)啟第二次事件循環(huán),從宏任務(wù)中選取任務(wù)執(zhí)行。此時(shí)宏任務(wù)里只有timeou_1任務(wù),js線程選取timeou_1執(zhí)行,控制臺(tái)打印timeou_1;
  9. 執(zhí)行完timeou_1,接著要依此執(zhí)行微任務(wù)里的任務(wù),現(xiàn)在微任務(wù)里沒(méi)有任務(wù),所以第二次事件循環(huán)結(jié)束;
  10. 此時(shí)宏任務(wù)、微任務(wù)都為空,js線程循環(huán)等待新任務(wù)。

事件回調(diào)任務(wù)優(yōu)先級(jí)較高

宏任務(wù)中,任務(wù)一般會(huì)按照先進(jìn)先出的原則進(jìn)行調(diào)度,但是如果宏任務(wù)中同時(shí)存在事件觸發(fā)線程觸發(fā)的任務(wù),則會(huì)優(yōu)先調(diào)度該任務(wù)。

分析一個(gè)例子:

<!DOCTYPE html>
<html lang="en">
  <body>
    <button id="btn">button</button>
    <script>
      document.getElementById("btn").onclick = function handleClick() {
        console.log("click btn");
      };
      setTimeout(function timeoutFn() {
        console.log("timeoutFn");
      }, 0);
      document.getElementById("btn").click();
    </script>
  </body>
</html>
  1. js線程執(zhí)行整體代碼script;
  2. 為btn添加監(jiān)聽(tīng)事件;
  3. 時(shí)間觸發(fā)線程將timeoutFn加入宏任務(wù);
  4. 觸發(fā)點(diǎn)擊btn事件,將handleClick加入宏任務(wù);
  5. 執(zhí)行完整體代碼script,因?yàn)槲⑷蝿?wù)為空,本次事件循環(huán)結(jié)束;
  6. 第二次事件循環(huán),宏任務(wù)中同時(shí)存在時(shí)間觸發(fā)線程回調(diào)timeoutFn和事件觸發(fā)線程回調(diào)handleClick,雖然timeoutFn先進(jìn)入宏隊(duì)列但事件回調(diào)任務(wù)優(yōu)先級(jí)高,優(yōu)先調(diào)度handleClick,輸出click btn。微任務(wù)中沒(méi)有任務(wù)本次事件循環(huán)結(jié)束;
  7. 第三次事件循環(huán),宏任務(wù)中只有timeoutFn,js線程選取 timeoutFn 執(zhí)行,輸出 timeoutFn。微任務(wù)中沒(méi)有任務(wù)本次事件循環(huán)結(jié)束;
  8. 此時(shí)宏任務(wù)、微任務(wù)都為空,js線程循環(huán)等待新任務(wù)。

參考:

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

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

  • 前言 想要了解一門(mén)語(yǔ)言,最好的辦法就是了解它的運(yùn)行機(jī)制。掌握了運(yùn)行機(jī)制,能夠讓我們?cè)陂_(kāi)發(fā)中少走許多彎路,寫(xiě)出高質(zhì)量...
    moofyu閱讀 404評(píng)論 0 1
  • 新建bat文件:*.bat 腳本文件,新建“文本文檔”,修改文本文檔文件后綴為 ".bat" 使用bat文件:無(wú)參...
    宇宙小神特別萌閱讀 1,694評(píng)論 0 2
  • 目錄:1、Hexo 啟用next主題模板2、更改Next主題為中文3、增加標(biāo)簽頁(yè)和分類(lèi)頁(yè)4、使用標(biāo)簽頁(yè)和分類(lèi)頁(yè)5、...
    宇宙小神特別萌閱讀 1,952評(píng)論 1 3
  • 宏定義對(duì)比函數(shù)的優(yōu)點(diǎn) 要寫(xiě)好C語(yǔ)言,漂亮的宏定義是非常重要的。宏定義可以幫助我們防止出錯(cuò),提高代碼的可移植性和可讀...
    fangyuu閱讀 108評(píng)論 0 0
  • 2020-04-10 中原焦點(diǎn)團(tuán)隊(duì) 肖巧風(fēng) 焦點(diǎn)解決初級(jí)網(wǎng)絡(luò)班第21期 堅(jiān)持第78天原創(chuàng)分享 總約練81次 挑戰(zhàn)三...
    鳳舞九天閱讀 311評(píng)論 0 0

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