来自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)
答案 0 :(得分:1)
当您点击该元素时,您自然会先输出click
,因为您上面有一个点击事件处理程序,并且单词的日志点击了&#39;在click事件处理函数中发生的第一个事件。
接下来是setTimeout(function() {}, 0);
。这会暂停JavaScript的执行,就像C中的线程/进程产量一样。它直到稍后才执行,所以我们稍后会再回过头来看。
因为您实际上没有做任何承诺,它会立即解决,退出第二。
突变发生在第三,因为DOM是从上到下读取的,并且您在promise解析后直接改变data-random
属性。
最后,现在DOM已经完成读取,超时结束第四次。
由于 a separate execution context ,timeout
从内部<div>
被记录两次,从而被调用。这可以通过以下事实看出:console.log(this)
中的onclick
不提供与setTimeout(function() {console.log(this)}, 0);
相同的上下文。由于 bubbling 与延迟的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);
&#13;
<div class="outer">Outer
<div class="inner">Inner</div>
</div>
&#13;
请注意,不同的浏览器会以不同的方式处由于代码逻辑,我假设 Chrome(我的答案基于此)正确处理此问题。
Firefox在承诺之前处理突变:
click
mutate
promise
promise
timeout
timeout
Edge在承诺之前处理突变和超时:
click
mutate
timeout
promise
timeout
promise
IE根本无法处理承诺,导致语法错误。
希望这有帮助! :)