[英]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
我正在努力看情況如何。 執行應該是
考慮到這一點,我期望輸出日志:
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
click
, promise
和mutate
日志將總是一個接一個地乘以您同時單擊的元素數。 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.