From Jake Archibald 's blog
Fiddle (Click on Hey): 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);
When running this piece for the inner div
the results I get are
click
mutate
click
mutate
promise
promise
timeout
timeout
and I am struggling to see how this is the case. The Execution should be
With this in mind, I am expecting the log to output instead:
click
promise
mutate
click
promise
mutate
timeout
timeout
Not sure why promises
are being executed only after two of the click's event handler has been processed. The very first promise should ideally execute after the first mutate
but we can see that it is clearly not the case. Anyone know why? (Using firefox 54.0)
When you click on the element, you naturally get click
outputted first, because you have a click event handler on it, and the log of the word 'click' in the first thing to happen in the click event handler function.
Next up is setTimeout(function() {}, 0);
. This pauses JavaScript's execution, and is like a thread/process yield in C. It doesn't execute until later, so we'll come back to that in a bit.
Because you're not actually doing anything with the promise, it resolves instantly, logging out second .
The mutation happens third because the DOM is read top-to-bottom, and you are mutating the data-random
attribute directly after the promise resolves.
Finally, now that the DOM has finished being read, the timeout finishes fourth .
The timeout
gets logged twice from the inner <div>
due to a separate execution context to where it was called from. This can be seen by the fact that console.log(this)
inside an onclick
does not provide the same context as setTimeout(function() {console.log(this)}, 0);
. Due to bubbling in conjunction with the delayed setTimeout
, it attempts to fire first from the child <div>
, and then also from the parent <div>
(which you technically clicked on).
Thus, you end up with:
click
promise
mutate
timeout
timeout
The click
, promise
and mutate
logs will always come one after another, multiplied by the number of elements that you are clicking on simultaneously. The timeout
logs will always come last.
// 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>
Note that different browsers process these differently. I'd assume that Chrome (which my answer is based off on) handles this correctly, due to the code logic.
Firefox handles mutations before promises:
click
mutate
promise
promise
timeout
timeout
Edge handles both mutations and timeouts before promises:
click
mutate
timeout
promise
timeout
promise
IE can't handle promises at all, throwing a syntax error.
Hope this helps! :)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.