-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Proposal: self.queueMicrotask(f) #512
Comments
This makes sense as a primitive to have. The only concern is what we do once it starts getting abused (see setTimeout throttling). Of course we'd have to figure that out for Promise and MutationObserver too.... |
I would also suggest posting to the Mozilla dev-platform mailing list to get a wider set of Mozilla people looking at this. I can do that for you if you want; please let me know. |
That'd be lovely if you could; thank you. |
https://groups.google.com/forum/#!topic/mozilla.dev.platform/NoKg9nX34vE or https://lists.mozilla.org/pipermail/dev-platform/2016-January/013056.html depending on how you prefer to read your mailing list threads. |
What is the difference between |
setTimeout returns to the event loop and processes events. |
For more information on that question I'd suggest reading the spec which has detailed sections on setTimeout and on enqueuing a microtask. |
Abusing is an issue, and yes, we may need to do something to that with MutationObserver and We should think about abusing issues before we add the API. But in general sounds like a good idea. |
I think abuse is taken care of by the slow script dialog clause already: https://html.spec.whatwg.org/#killing-scripts |
I'm not so sure. Initially microtasks were for one particular case only - running MutationObserver callbacks, and in that case abusing is less likely. Promises make abusing way more likely, and raw microtask callbacks perhaps even more. But it is not clear to me what we could do to prevent abuse. |
Well, whatever you want to do, I imagine it will fall under one of
so I still think it's covered by the existing spec. |
Except that if we add some limitation, it needs to work consistently across browsers. |
Why? The slow script dialog doesn't work consistently across browsers today. Recursive microtasks are essentially the same as recursive functions: it allows an extra stack frame to unwind in between, but there's otherwise no difference. So I think they should be treated the same way. |
ok, so you're worried about blocking UI totally with effectively while(true); |
I don't think enqueueMicrotask is really an alternative to setTimeout. It's specifically used when people want to do work before rendering. In other words, it's for choosing between function f(cb) {
if (someTest) cb();
else {
doAsyncThings().then(cb);
}
} (which is bad since it's sometimes-sync, sometimes-async) versus function f(cb) {
if (someTest) enqueueMicrotask(cb);
else {
doAsyncThings().then(cb);
}
} People can abuse it by not yielding to the event loop to allow rendering/RAF, for sure. But they can also do that with while(true). If you want to yield to the event loop, you don't use enqueueMicrotask. |
I would like to offer my point of view as the Angular author.
So these things all fill a different niche. Yes, all of them can be misused, but let's not that be enemy of useful. |
Why is this not proposed as a ECMAScript feature? |
ECMAScript doesn't have a good concept of the event loop. |
For those looking for an explanation of tasks (eg |
@annevk - however, Promise already uses microtasks... It would be very weird to have a primitive on which the language depends, be defined separately, in a web specific context. |
@mhevery still trying to understand the use cases here. If you want to do something before rendering, you could just use rAF. Why does that not work for you? What you mean with "need to do something outside my current frame"? What is 'frame' here? Random thought. it feels like people often want setTimeout(,0) but with guarantee it is called before the next rAF. So, true asynchronousness, but prioritized over rAF. If such scheduling type was added, the method could even throw or return false if we're about to delay rAF because of it. (I'm just trying to understand both pros and cons and also use cases for this. In general I'm in favor of adding this API, but we're too good at adding APIs to the platform and realizing later that it wasn't quite right. ) |
I suspect that the lack of public microtask api is why a lot of frameworks have their own next tick method, see
|
@SmauG Yes Promises is a way to schedule microtasks, but in my opinion it is backwards. The primitive is |
the whole point of rAF is to not flicker, but do async stuff as rarely as possible right before rendering is updated. Sure, if you request a new animation frame inside rAF, then that gets called later. Hmm, 100s of microtasks. That certainly sounds like abuse of microtasks. Doing too much stuff synchronously (remember, microtask is synchronous from browser point of view). So, still wondering. Is there some other kind of, truly asynchronous API which frameworks could use? |
@smaug---- if frameworks are already doing this today presumably they have a reason for that. And other than a microtask API there's really nothing else that'd guarantee the thing happening after the current activity, but before the next task (except for the hacks frameworks are already using). |
That's not true. Promises use a host-environment agnostic concept called "jobs". When hosted by a user agent implementing the HTML Standard, jobs map to the HTML concept of microtasks. See https://html.spec.whatwg.org/#integration-with-the-javascript-job-queue. This is clearly out of scope for ECMAScript, and the committee has (often violently) pushed back against the very word "microtasks" when it is brought up in TC39 meetings. |
What are you talking about? I have way over 100 lines of code that run synchronously. Sometimes I want them to run a specific order, so I use microtasks to ensure that ordering. Other times I just let them run in the source order, but you don't call that an "abuse." |
I talked to @smaug---- on IRC. His issue is that user input only comes in after a tasks completes (in a new task). So adding a mechanism to queue a lot of "event-loop blocking" work is a concern. His suggestion is to have an API that ensures the callback is invoked before next- Since you can already have a microtask API through a polyfill, perhaps we should have both. |
That seems like a reasonable separate feature request in a separate GitHub issue. I am curious if any framework authors are interested in that, or just Gecko. |
User event comes in, framework starts processing it. In the process there Yes we are probably busting our frame budget, but I don't don't believe On Tue, Jan 19, 2016 at 7:01 AM smaug---- [email protected] wrote:
|
@mhevery Thank you for the example. Just to make sure I understand it properly, is the framework trying to wait until the entire Promise chain completes, even if in the async case, or is it just trying to wait until all the things that can be serviced out of cached data are done before rendering? I assume the latter, right?
The whole point of rAF is that there is such a guarantee: if you make some changes to the DOM or styles and in the same task or ensuing microtasks post an rAF callback, then that rAF callback will be called before the browser renders to screen any of the DOM/style changes you made.
Again, just to make sure I understand correctly, the use case here is that the framework wants to render once all the cached stuff has been applied, without necessarily waiting for the truly async tasks, and the framework consumer wants to do some work after the framework renders but before the browser then renders the output of the framework. Is that a correct summary of the problem? |
Yes, wait until everything that can be serviced is.
OK, I stand corrected, did not realized that. But if we use What we need is a way to schedule work on the current microtask queue.
Yes correct. Just adding, that I keep using render, but it really should be data propagation. The fact that some data propagates to the DOM and other propagates to the other part of the application is important. While DOM propagation could be delayed, (since there is no side-effect) propagating to the rest of the app can not be delayed, since we need to treat it as transaction, and fully complete it before we allow subsequent event processing. |
Thank you, I appreciate this example. That said, even if the framework were to append to the current microtask queue, that just pushes the problem back a level: now the |
But we don't guarantee that. We only guarantee that VM turns will see it consistent.
correct, since every VM turn is started with an event ( |
I think there was a similar try with setImmediate, is there any major reason to make a new spec? |
|
Resurrecting this old thread: Chrome is currently implementing the proposal as specced in #2789. Are any other vendors interested in shipping queueMicrotask()? Lots of discussion with Gecko folks above; what about Safari (@cdumez @hober) or Edge (@dstorey @travisleithead)? Note how #2789 has web developer-facing text about when this is appropriate which should help at least a bit with some of the Gecko discussions here. |
@dstorey, @arronei and I are glad to see the Author note. I'm a little concerned about developers easily falling into the trap of scheduling the next callback from within the callback (e.g., like |
Thanks @travisleithead and folks! We could indeed add some examples drawing explicit equivalence between recursive queueMicrotask and recursive sync functions / sync while loops. I'm a little unsure how we should interpret "No objections here" for the purposes of https://whatwg.org/working-mode#additions; would you support adding this to the specification? |
Yes |
Closes #512. Tests: web-platform-tests/wpt#6334
Closes whatwg#512. Tests: web-platform-tests/wpt#6334
Closes whatwg#512. Tests: web-platform-tests/wpt#6334
Closes whatwg#512. Tests: web-platform-tests/wpt#6334
In talking with the Angular team (mostly @mhevery), there is interest in a simple low-level method for enqueuing a microtask from author code. I've heard this from a number of authors in the past. It seems simple enough and easy to add to the spec, if we can get any other implementations besides Chrome interested.
Right now authors are doing this via a number of hacks, like creating a text node and a MutationObserver and twiddling the text node every time they want to trigger a microtask, or using
Promise.resolve().then(f)
(which creates a promise object and stores any thrown errors there, instead of letting them propagate to "report an exception").There are many use cases, which I'm sure we can assemble in depth, but let me just start with the following reasons which will hopefully be enough to convince people:
setTimeout(f, 0)
.I'd like to first focus this thread on finding implementer support: if we spec this, will you implement it? After that, we can start bikeshedding the name; please don't do so beforehand.
/ccing some implementers: @hober @travisleithead @bzbarsky
The text was updated successfully, but these errors were encountered: