簡體   English   中英

JavaScript任務計划,宏任務和微任務

[英]JavaScript task scheduling, Macrotask and Microtasks

傑克·阿奇博爾德Jake Archibald )的博客

小提琴(點擊嘿): https : //jsfiddle.net/1rpzycLf/

HTML:

<div class="outer">
  <div class="inner"></div>
</div>

JS:

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

當為inner div運行此片段時,我得到的結果是

click
mutate
click
mutate
promise
promise
timeout
timeout

我正在努力看情況如何。 執行應該是

  1. 第一處理程序(宏任務)
  2. 處理所有微任務
  3. 第二處理程序(宏任務)
  4. 處理所有微任務
  5. SetTimeout(宏任務)
  6. SetTimeout(宏任務)

考慮到這一點,我期望輸出日志:

click
promise
mutate
click
promise
mutate
timeout
timeout

不確定為什么僅在兩次單擊事件處理程序處理后才執行promises 理想情況下,第一個承諾應該在第一個mutate之后執行,但是我們可以看到事實顯然並非如此。 有人知道為什么嗎? (使用firefox 54.0)

當您單擊該元素時,自然會首先輸出click ,因為您上面有一個click事件處理程序,並且單擊事件處理函數中首先發生的單詞“ click”的日志。

接下來是setTimeout(function() {}, 0); 這暫停了JavaScript的執行,就像C語言中的線程/進程產量一樣。它直到稍后才執行,因此我們將稍等一下。

因為你沒有真正做什么用的承諾,它解決了瞬間, 第二注銷。

因為DOM是從上到下讀取的,所以突變發生在第三位 ,並且您在promise解析之后直接對data-random屬性進行突變。

最終,既然DOM已經完成讀取,那么超時將排在第四位

timeout從內部<div>被記錄兩次,這是因為從其調用的地方有單獨的執行上下文 這可以通過這樣的事實可以看出, console.log(this)內的onclick 提供相同的上下文中setTimeout(function() {console.log(this)}, 0); 由於冒泡以及延遲的setTimeout ,它首先嘗試從子<div>觸發,然后又從 <div> (從技術上單擊)觸發。

因此,您最終得到:

click
promise
mutate
timeout
timeout

clickpromisemutate日志將總是一個接一個地乘以您同時單擊的元素數。 timeout日志將始終排在最后。

 // 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.clear(); // Added for clarity 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); 
 <div class="outer">Outer <div class="inner">Inner</div> </div> 

請注意,不同的瀏覽器對這些內容的處理方式也不同。 認為 Chrome瀏覽器(其中我的答案是基於關閉的)正確處理此,由於代碼邏輯。

Firefox處理承諾之前的突變:

click
mutate
promise
promise
timeout
timeout

Edge在承諾之前處理變異和超時:

click
mutate
timeout
promise
timeout
promise

IE根本無法處理承諾,會引發語法錯誤。

希望這可以幫助! :)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM