Given our recent performance push, I thought I'd bring this topic up again.
When writing loops using async functions in browser code, it's still
very easy to cause jank. For example, a trivial function:
> async function janky() {
> for (let i = 0; i < 100000; i++) {
> await Promise.resolve();
> }
> }
>
> janky().then(() => console.log("done"));
will cause the browser to hang. While that's not considered a bug in the
implementation of the promise scheduler, and might not be particularly
surprising in that trivial example, lots of real-world code can still
hit this case - which both isn't obvious from casual inspection, and
even if it was, doesn't have an obvious solution.
Concretely, we struck this a couple of years ago in bug 1186714 -
creating a backup of all bookmarks ends up looking alot like the loop
above. In addition, the Sync team is moving away from nested event loops
towards promises, and our work to date is hitting this problem.
In bug 1186714, we solved the problem by inserting code into the loop
that looks like:
> if (i % 50 == 0) {
> await new Promise(resolve => {
> Services.tm.dispatchToMainThread(resolve);
> });
> }
http://searchfox.org/mozilla-central/rev/f55349994fdac101d121b11dac769f3f17fbec4b/toolkit/components/places/PlacesUtils.jsm#2022
so we explicitly yield to the event loop every 50 iterations. However,
this isn't optimal as the 50 is obviously a magic number, determined by
experimentation on a couple of machines - when running on low spec
hardware, this loop is almost certainly still janky. If we try and err
on the side of caution (eg, yielding every iteration) we see the wall
time of the loop take a massive hit (around twice as long in that bug).
I'm wondering if there are any ideas about how to solve this optimally?
Naively, it seems that the (broadest sense of the term) "platform" might
be able to help here using it's knowledge of the event-loop state - eg,
a function that indicates "are we about to starve the event loop and
become janky?", or possibly even the whole hog (ie, "please yield to the
event loop if you think now is a good time, otherwise just hand back a
pre-resolved promise").
Or maybe there are simpler options I've overlooked?
Thanks,
Mark
_______________________________________________
dev-platform mailing list
[email protected]
https://lists.mozilla.org/listinfo/dev-platform