国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

什么是瀏覽器的事件循環(Event Loop)?

JerryC / 868人閱讀

摘要:本文圍繞瀏覽器的事件循環,而有自己的另一套事件循環機制,不在本文討論范圍。現在我們知道了瀏覽器運行時有一個叫事件循環的機制。將事件循環的當前運行任務設置為。對于相應事件循環的每個環境設置對象通知它們哪些為。

本文圍繞瀏覽器的事件循環,而node.js有自己的另一套事件循環機制,不在本文討論范圍。網上的許多相關技術文章提到了process.nextTicksetImmediate兩個node.js的API,這里不予討論。

先看HTML標準的一系列解釋:

為了協調事件(event),用戶交互(user interaction),腳本(script),渲染(rendering),網絡(networking)等,用戶代理(user agent)必須使用事件循環(event loops)。

有兩類事件循環:一種針對瀏覽上下文(browsing context),還有一種針對worker(web worker)。

現在我們知道了瀏覽器運行時有一個叫事件循環的機制。

一個事件循環有一個或者多個任務隊列(task queues)。任務隊列是task的有序列表,這些task是以下工作的對應算法:Events,Parsing,Callbacks,Using a resource,Reacting to DOM manipulation。

每一個任務都來自一個特定的任務源(task source)。所有來自一個特定任務源并且屬于特定事件循環的任務,通常必須被加入到同一個任務隊列中,但是來自不同任務源的任務可能會放在不同的任務隊列中。

舉個例子,用戶代理有一個處理鼠標和鍵盤事件的任務隊列。用戶代理可以給這個隊列比其他隊列多3/4的執行時間,以確保交互的響應而不讓其他任務隊列餓死(starving),并且不會亂序處理任何一個任務隊列的事件。

每個事件循環都有一個進入microtask檢查點(performing a microtask checkpoint)的flag標志,這個標志初始為false。它被用來組織反復調用‘進入microtask檢查點’的算法。

總結一下,一個事件循環里有很多個任務隊列(task queues)來自不同任務源,每一個任務隊列里的任務是嚴格按照先進先出的順序執行的,但是不同任務隊列的任務的執行順序是不確定的。按我的理解就是,瀏覽器會自己調度不同任務隊列。網上很多文章會提到macrotask這個概念,其實就是指代了標準里闡述的task

標準同時還提到了microtask的概念,也就是微任務。看一下標準闡述的事件循環的進程模型:

選擇當前要執行的任務隊列,選擇一個最先進入任務隊列的任務,如果沒有任務可以選擇,則會跳轉至microtask的執行步驟。

將事件循環的當前運行任務設置為已選擇的任務。

運行任務。

將事件循環的當前運行任務設置為null。

將運行完的任務從任務隊列中移除。

microtasks步驟:進入microtask檢查點(performing a microtask checkpoint )。

更新界面渲染。

返回第一步。

執行進入microtask檢查點時,用戶代理會執行以下步驟:

設置進入microtask檢查點的標志為true。

當事件循環的微任務隊列不為空時:選擇一個最先進入microtask隊列的microtask;設置事件循環的當前運行任務為已選擇的microtask;運行microtask;設置事件循環的當前運行任務為null;將運行結束的microtask從microtask隊列中移除。

對于相應事件循環的每個環境設置對象(environment settings object),通知它們哪些promise為rejected。

清理indexedDB的事務。

設置進入microtask檢查點的標志為false。

現在我們知道了。在事件循環中,用戶代理會不斷從task隊列中按順序取task執行,每執行完一個task都會檢查microtask隊列是否為空(執行完一個task的具體標志是函數執行棧為空),如果不為空則會一次性執行完所有microtask。然后再進入下一個循環去task隊列中取下一個task執行...

那么哪些行為屬于task或者microtask呢?標準沒有闡述,但各種技術文章總結都如下:

macrotasks: script(整體代碼), setTimeout, setInterval, setImmediate, I/O, UI rendering

microtasks: process.nextTick, Promises, Object.observe(廢棄), MutationObserver

來看一個例子:

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");

(代碼來自Tasks, microtasks, queues and schedules,推薦觀看原文的代碼可視化執行步驟

如果你測試的瀏覽器支持的Promise不支持Promise/A+標準,或是你使用了其他Promise polyfill,運行結果可能有差異。

運行結果是:

script start
script end
promise1
promise2
setTimeout

解釋一下過程。

一開始task隊列中只有script,則script中所有函數放入函數執行棧執行,代碼按順序執行。

接著遇到了setTimeout,它的作用是0ms后將回調函數放入task隊列中,也就是說這個函數將在下一個事件循環中執行(注意這時候setTimeout執行完畢就返回了)。

接著遇到了Promise,按照前面所述Promise屬于microtask,所以第一個.then()會放入microtask隊列。

當所有script代碼執行完畢后,此時函數執行棧為空。開始檢查microtask隊列,此時隊列不為空,執行.then()的回調函數輸出"promise1",由于.then()返回的依然是promise,所以第二個.then()會放入microtask隊列繼續執行,輸出"promise2"。

此時microtask隊列為空了,進入下一個事件循環,檢查task隊列發現了setTimeout的回調函數,立即執行回調函數輸出"setTimeout",代碼執行完畢。

繼續看一個更有趣的例子:

HTML代碼:

JavaScript代碼:

// Let"s get hold of those elements
var outer = document.querySelector(".outer");
var inner = document.querySelector(".inner");

// Let"s listen for attribute changes on the
// outer element
new MutationObserver(function() {
  console.log("mutate");
}).observe(outer, {
  attributes: true
});

// Here"s a click listener…
function onClick() {
  console.log("click");

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

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

  outer.setAttribute("data-random", Math.random());
}

// …which we"ll attach to both elements
inner.addEventListener("click", onClick);
outer.addEventListener("click", onClick);

(代碼來自Tasks, microtasks, queues and schedules,推薦觀看原文的代碼可視化執行步驟
點擊內框后,結果如下:

click
promise
mutate
click
promise
mutate
timeout
timeout

解釋一下過程:
點擊inner輸出"click",Promise和設置outer屬性會依次把Promise和MutationObserver推入microtask隊列,setTimeout則會推入task隊列。此時執行棧為空,雖然后面還有冒泡觸發,但是此時microtask隊列會先執行,所以依次輸入"promise"和"mutate"。接下來事件冒泡再次觸發事件,過程和開始一樣。接著代碼執行完畢,此時進入下一次事件循環,執行task隊列中的任務,輸出兩個"timeout"。

好了,如果你理解了這個,那么現在換一下事件觸發的方式。在上面的代碼后面加上

inner.click()

思考看看會有什么不同。

運行結果:

click
click
promise
mutate
promise
timeout
timeout

造成這個差異的結果是什么呢?因為第一次執行完第一個click事件后函數執行棧并不為空。
具體代碼運行解釋,可以查看Tasks, microtasks, queues and schedules。

本文參考:
html.spec.whatwg.org
difference-between-javascript-macrotask-and-microtask
Event loop

墻裂建議大家閱讀HTML標準里闡述的Event Loop,歡迎指正和建議。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/87228.html

相關文章

  • 一篇文章教會你Event loop——覽器和Node

    摘要:如果沒到毫秒,那么階段就會跳過,進入階段,先執行的回調函數。參考文檔什么是瀏覽器的事件循環不要混淆和瀏覽器中的定時器詳解瀏覽器和不同的事件循環深入理解事件循環機制篇中的執行機制 最近對Event loop比較感興趣,所以了解了一下。但是發現整個Event loop盡管有很多篇文章,但是沒有一篇可以看完就對它所有內容都了解的文章。大部分的文章都只闡述了瀏覽器或者Node二者之一,沒有對比...

    Leck1e 評論0 收藏0
  • 徹底搞懂覽器Event-loop

    摘要:檢查宏任務隊列,發現有的回調函數立即執行回調函數輸出。接著遇到它的作用是在后將回調函數放到宏任務隊列中這個任務在再下一次的事件循環中執行。 為什么會寫這篇博文呢? 前段時間,和頭條的小伙伴聊天問頭條面試前端會問哪些問題,他稱如果是他面試的話,event-loop肯定是要問的。那天聊了蠻多,event-loop算是給我留下了很深的印象,原因很簡單,因為之前我從未深入了解過,如果是面試的時...

    source 評論0 收藏0
  • JavaScript 事件循環(譯文JavaScript Event Loop

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

    K_B_Z 評論0 收藏0
  • 關于覽器Event Loop

    摘要:的宿主最開始本身就是瀏覽器,處理用戶的交互事件。既然是單線程的,那就意味著任務需要排隊,只有前一個任務執行完畢,下一個任務才能開始,于是就有了任務隊列。事件循環有兩種用于瀏覽上下文的事件循環和用于的事件循環。 最近看到Event Loop這個詞出現的頻率有點高,于是查閱各方資料在此記錄一下。 先不說概念,我們來看段代碼: console.log(script start); setT...

    youkede 評論0 收藏0
  • JavaScript執行機制、事件循環

    摘要:曾經的理解首先,是單線程語言,也就意味著同一個時間只能做一件事,那么為什么不是多線程呢這樣還能提高效率啊假定同時有兩個線程,一個線程在某個節點上編輯了內容,而另一個線程刪除了這個節點,這時瀏覽器就很懵逼了,到底以執行哪個操作呢所以,設計者把 Event Loop曾經的理解 首先,JS是單線程語言,也就意味著同一個時間只能做一件事,那么 為什么JavaScript不是多線程呢?這樣還能提...

    rose 評論0 收藏0
  • 10分鐘理解JS引擎執行機制

    摘要:深入理解引擎的執行機制靈魂三問為什么是單線程的為什么需要異步單線程又是如何實現異步的呢中的中的說說首先請牢記點是單線程語言的是的執行機制。 深入理解JS引擎的執行機制 1.靈魂三問 : JS為什么是單線程的? 為什么需要異步? 單線程又是如何實現異步的呢? 2.JS中的event loop(1) 3.JS中的event loop(2) 4.說說setTimeout 首先,請牢記2...

    zzbo 評論0 收藏0

發表評論

0條評論

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