成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

你不得不知的Event Loop

call_me_R / 698人閱讀

摘要:具體的可以用下面的圖來大致說明一下同步和異步任務(wù)分別進入不同的執(zhí)行環(huán)境,同步的進入主線程,即主執(zhí)行棧,異步的進入。主線程內(nèi)的任務(wù)執(zhí)行完畢為空,會去讀取對應(yīng)的任務(wù),推入主線程執(zhí)行。

前言

眾所周知,JavaScript是一門單線程語言,雖然在html5中提出了Web-Worker,但這并未改變JavaScript是單線程這一核心??煽碒TML規(guī)范中的這段話:

To coordinate events, user interaction, scripts, rendering, networking, and so forth, user agents must use event loops as described in this section. There are two kinds of event loops: those for browsing contexts, and those for workers.

為了協(xié)調(diào)事件、用戶交互、腳本、UI 渲染和網(wǎng)絡(luò)處理等行為,用戶引擎必須使用event loops。Event Loop包含兩類:一類是基于Browsing Context,一種是基于Worker,二者是獨立運行的。
下面本文用一個例子,著重講解下基于Browsing Context的事件循環(huán)機制。

來看下面這段JavaScript代碼:

console.log("script start");

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

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

console.log("script end");

先猜測一下這段代碼的輸出順序是什么,再去瀏覽器控制臺輸入一下,看看實際輸出的順序和你猜測出的順序是否一致,如果一致,那就說明,你對JavaScript的事件循環(huán)機制還是有一定了解的,繼續(xù)往下看可以鞏固下你的知識;而如果實際輸出的順序和你的猜測不一致,那么本文下面的部分會為你答疑解惑。

任務(wù)隊列

所有的任務(wù)可以分為同步任務(wù)和異步任務(wù),同步任務(wù),顧名思義,就是立即執(zhí)行的任務(wù),同步任務(wù)一般會直接進入到主線程中執(zhí)行;而異步任務(wù),就是異步執(zhí)行的任務(wù),比如ajax網(wǎng)絡(luò)請求,setTimeout定時函數(shù)等都屬于異步任務(wù),異步任務(wù)會通過任務(wù)隊列(Event Queue)的機制來進行協(xié)調(diào)。具體的可以用下面的圖來大致說明一下:

同步和異步任務(wù)分別進入不同的執(zhí)行環(huán)境,同步的進入主線程,即主執(zhí)行棧,異步的進入Event Queue。主線程內(nèi)的任務(wù)執(zhí)行完畢為空,會去Event Queue讀取對應(yīng)的任務(wù),推入主線程執(zhí)行。
上述過程的不斷重復(fù)就是我們說的Event Loop(事件循環(huán))。

在事件循環(huán)中,每進行一次循環(huán)操作稱為tick,通過閱讀規(guī)范可知,每一次tick的任務(wù)處理模型是比較復(fù)雜的,其關(guān)鍵的步驟可以總結(jié)如下:

在此次tick中選擇最先進入隊列的任務(wù)(oldest task),如果有則執(zhí)行(一次)

檢查是否存在Microtasks,如果存在則不停地執(zhí)行,直至清空Microtask Queue

更新render

主線程重復(fù)執(zhí)行上述步驟

可以用一張圖來說明下流程:

這里相信有人會想問,什么是microtasks?規(guī)范中規(guī)定,task分為兩大類, 分別是Macro Task (宏任務(wù))和Micro Task(微任務(wù)), 并且每個宏任務(wù)結(jié)束后, 都要清空所有的微任務(wù),這里的Macro Task也是我們常說的task,有些文章并沒有對其做區(qū)分,后面文章中所提及的task皆看做宏任務(wù)(macro task)。

(macro)task主要包含:script(整體代碼)、setTimeout、setInterval、I/O、UI交互事件、setImmediate(Node.js 環(huán)境)

microtask主要包含:Promise、MutaionObserver、process.nextTick(Node.js 環(huán)境)

setTimeout/Promise等API便是任務(wù)源,而進入任務(wù)隊列的是由他們指定的具體執(zhí)行任務(wù)。來自不同任務(wù)源的任務(wù)會進入到不同的任務(wù)隊列。其中setTimeout與setInterval是同源的。

分析示例代碼

千言萬語,不如就著例子講來的清楚。下面我們可以按照規(guī)范,一步步執(zhí)行解析下上面的例子,先貼一下例子代碼(免得你往上翻)。

console.log("script start");

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

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

console.log("script end");

整體script作為第一個宏任務(wù)進入主線程,遇到console.log,輸出script start

遇到setTimeout,其回調(diào)函數(shù)被分發(fā)到宏任務(wù)Event Queue中

遇到Promise,其then函數(shù)被分到到微任務(wù)Event Queue中,記為then1,之后又遇到了then函數(shù),將其分到微任務(wù)Event Queue中,記為then2

遇到console.log,輸出script end

至此,Event Queue中存在三個任務(wù),如下表:

宏任務(wù) 微任務(wù)
setTimeout then1 then2

執(zhí)行微任務(wù),首先執(zhí)行then1,輸出promise1,然后執(zhí)行then2,輸出promise2,這樣就清空了所有微任務(wù)

執(zhí)行setTimeout任務(wù),輸出setTimeout

至此,輸出的順序是:script start, script end, promise1, promise2, setTimeout

so,你猜對了嗎?

看看你掌握了沒

再來一個題目,來做個練習(xí):

console.log("script start");

setTimeout(function() {
  console.log("timeout1");
}, 10);

new Promise(resolve => {
    console.log("promise1");
    resolve();
    setTimeout(() => console.log("timeout2"), 10);
}).then(function() {
    console.log("then1")
})

console.log("script end");

這個題目就稍微有點復(fù)雜了,我們再分析下:

首先,事件循環(huán)從宏任務(wù)(macrotask)隊列開始,最初始,宏任務(wù)隊列中,只有一個script(整體代碼)任務(wù);當(dāng)遇到任務(wù)源(task source)時,則會先分發(fā)任務(wù)到對應(yīng)的任務(wù)隊列中去。所以,就和上面例子類似,首先遇到了console.log,輸出script start;
接著往下走,遇到setTimeout任務(wù)源,將其分發(fā)到任務(wù)隊列中去,記為timeout1;
接著遇到promise,new promise中的代碼立即執(zhí)行,輸出promise1,然后執(zhí)行resolve,遇到setTimeout,將其分發(fā)到任務(wù)隊列中去,記為timemout2,將其then分發(fā)到微任務(wù)隊列中去,記為then1;
接著遇到console.log代碼,直接輸出script end
接著檢查微任務(wù)隊列,發(fā)現(xiàn)有個then1微任務(wù),執(zhí)行,輸出then1
再檢查微任務(wù)隊列,發(fā)現(xiàn)已經(jīng)清空,則開始檢查宏任務(wù)隊列,執(zhí)行timeout1,輸出timeout1
接著執(zhí)行timeout2,輸出timeout2
至此,所有的都隊列都已清空,執(zhí)行完畢。其輸出的順序依次是:script start, promise1, script end, then1, timeout1, timeout2

用流程圖看更清晰:

總結(jié)

有個小tip:從規(guī)范來看,microtask優(yōu)先于task執(zhí)行,所以如果有需要優(yōu)先執(zhí)行的邏輯,放入microtask隊列會比task更早的被執(zhí)行。

最后的最后,記住,JavaScript是一門單線程語言。

參考文獻

這一次,徹底弄懂 JavaScript 執(zhí)行機制
Tasks, microtasks, queues and schedules
從一道題淺說 JavaScript 的事件循環(huán)

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/93418.html

相關(guān)文章

  • 一文掌握前端面試瀏覽器相關(guān)知識點

    摘要:決定了注冊的事件是捕獲事件還是冒泡事件。瀏覽器會自動進行通信,實現(xiàn)通信的關(guān)鍵是后端。該方式只能用于二級域名相同的情況下,比如和適用于該方式。中的中的和瀏覽器中的不相同。 事件機制 事件觸發(fā)三階段 事件觸發(fā)有三個階段 window 往事件觸發(fā)處傳播,遇到注冊的捕獲事件會觸發(fā) 傳播到事件觸發(fā)處時觸發(fā)注冊的事件 從事件觸發(fā)處往 window 傳播,遇到注冊的冒泡事件會觸發(fā) 事件觸發(fā)一般...

    anquan 評論0 收藏0
  • JavaScript 事件循環(huán)(譯文JavaScript Event Loop

    摘要:事件循環(huán)了解了在引擎中是如何工作了之后,來看下如何使用異步回調(diào)函數(shù)來避免代碼。從回調(diào)函數(shù)被放入后秒鐘,把移到中。由于事件循環(huán)持續(xù)地監(jiān)測調(diào)用棧是否已空,此時它一注意到調(diào)用??樟耍驼{(diào)用并創(chuàng)建一個新的調(diào)用棧。 聽多了JavaScript單線程,異步,V8,便會很想去知道JavaScript是如何利用單線程來實現(xiàn)所謂的異步的。我參考了一些文章,了解到一個很重要的詞匯:事件循環(huán)(Event L...

    K_B_Z 評論0 收藏0
  • 【轉(zhuǎn)】深入理解JS單線程機制【原文作者:MasterYao】

    摘要:的單線程,與它的用途有關(guān)。只要指定過回調(diào)函數(shù),這些事件發(fā)生時就會進入任務(wù)隊列,等待主線程讀取。四主線程從任務(wù)隊列中讀取事件,這個過程是循環(huán)不斷的,所以整個的這種運行機制又稱為事件循環(huán)。令人困惑的是,文檔中稱,指定的回調(diào)函數(shù),總是排在前面。 原文:http://www.cnblogs.com/Master... 一、為什么JavaScript是單線程? JavaScript語言的一大特點...

    LittleLiByte 評論0 收藏0
  • 2018成長了么?一份給前端技術(shù)清單

    摘要:由于個人精力有限,一些技術(shù)點的歸納可能有失偏頗,或者目前并未納入進來,因此上的清單內(nèi)容也會不斷更新。 2018 眼看就要過去了,今年的你相較去年技術(shù)上有怎樣的收獲呢? 記得年初的時候我給自己制定了一個學(xué)習(xí)計劃,現(xiàn)在回顧來看完成度還不錯。但仍有些遺憾,一些技術(shù)點沒有時間去好好學(xué)習(xí)。 在學(xué)習(xí)中我發(fā)現(xiàn),像文章這樣的知識往往是碎片化的,而前端涉及到的面很多,如果不將這些知識有效梳理,則無法形成...

    K_B_Z 評論0 收藏0

發(fā)表評論

0條評論

call_me_R

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<