Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Early queueMicroTask execution in relation to MutationObserver #924

Closed
Mellthas opened this issue Apr 1, 2021 · 5 comments
Closed

Early queueMicroTask execution in relation to MutationObserver #924

Mellthas opened this issue Apr 1, 2021 · 5 comments

Comments

@Mellthas
Copy link

Mellthas commented Apr 1, 2021

Similar example to the one in #855:

new MutationObserver(() => {
     console.log("first");
}).observe(document.body, { childList: true });

document.body.append('');

queueMicrotask(() => {
  console.log("second");
});

Which produces first, second in the latest Chrome and Firefox, but second, first in Firefox 68 ESR.

@zloirock
Copy link
Owner

zloirock commented Apr 1, 2021

Interesting, because here it should be based on MutationObserver.

@zloirock
Copy link
Owner

zloirock commented Apr 1, 2021

Yes, here microtask is based on MutationObserver. Since core-js is loaded before your script, the observer used in the polyfill is defined before your own observer in the list of callbacks, so it's called before. I don't see any proper way to fix it and I don't think that it's a big problem, more other, I can't find in the spec the place where the priority of MutationObserver queue is higher than queueMicrotask queue (I'm not an expert in HTML spec) - it's a microtask and I think that it's enough correct.

@Mellthas
Copy link
Author

Mellthas commented Apr 1, 2021

Not 100% sure how this is supposed to work either; but if I read https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/#whos-right correctly (click through the interactive example), the code above should be roughly equivalent to:

document.body.append('');

queueMicrotask(() => {
  console.log("first");
});

queueMicrotask(() => {
  console.log("second");
});

And I get the same issue with the following code using a Promise instead of queueMicrotask (testing in Firefox 68):

new MutationObserver(() => {
     console.log("first");
}).observe(document.body, { childList: true });

document.body.append('');

Promise.resolve().then(() => {
  console.log("second");
});

The use case is that I want to be sure that MutationObserver callbacks have been run after adding a node to the DOM, and I thought that I could do this with queueMicrotask.

@Mellthas
Copy link
Author

Mellthas commented Apr 1, 2021

If I force it to use the Promise-based polyfill in internals/microtask.js then the order is first, second in both cases.

@zloirock
Copy link
Owner

zloirock commented Apr 1, 2021

Yes, I remember this post. But you could imagine it as 2 separate microtask queues. I don't think that it somehow contradicts that.

Why it's called before your callback - in core-js queueMicrotask implementation, new MutationObserver(() => { ... }).observe( ... ) called at the library initialization, queueMicrotask set a callback to the queue and trigger changes of the observable element. We could create an observer and observable element on each queueMicrotask call - but it could cause memory leaking and it could be too heavy. Promise-based implementation could be much less correct and much heavier because the Promise can be non-standard.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants