[英]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.