rfcs
rfcs copied to clipboard
Render Aware Scheduler Interface
This RFC Proposes replacing @ember/runloop (Backburner.js) with an interface for common scheduling needs.
The interface describes intent for when work should be performed in relation to the native event queues and render cycle of the browser. The details of how that work is scheduled and flushed are up to the specific scheduler implementation, allowing for experiments in this space.
Additionally, this RFC proposes deprecations and alterations to associated async primitives such as RSVP to support this exploration.
Moving to the Exploring stage requires the consensus of the relevant teams. See :https://github.com/emberjs/rfcs#exploring I am removing the label.
What are the SSR impacts? (if we were to re-invest SSR in the most ideal way)
- what is settled?
- ignore idle? do we ignore it? -> flush idle queue? -> ensure flushed?
- how to test with idle?
if you have a lot of timings / queues, how do you prevent folks from just arbitrarily adding things to whatever the "next queue" is?
how do we suggest / teach when folks will want to use one queue over others?
Given that @ef4 and @wycats are generally in favor of this direction we agreed at the RFC review meeting to move to Exploring.
Thumbs up. We got into the details in the spec meeting and I think this is absolutely ready for Exploring.
Status update here: this is looking good, @runspired is leading experimentation in the implementation side as the next action before putting this forward as formal public API.
As an update: I ran AuditBoard's test suite replacing the RSVP flush with a native microtask instead of flushing in the runloop, and EmberData 4.12.x (which drops all RSVP and almost all runloop utilization). A few observations:
EmberData 4.12.x upgrade itself had a few timing things to work out, but it didn't take us too long to get through them despite ~12k tests, and they all fell into a bucket of bugs that wouldn't exist with the proposed scheduler.
RSVP: changing to flush with a microtask failed only 3 tests, all for an identical cause: In a route afterModel we had this:
scheduleOnce('afterRender', this, () => {
this.send('onSetBreadcrumb');
});
With RSVP flushing as a native microtask, this now runs after instead of before the completion handling of many promises associated with the transition. Were we to adopt this proposal though, this would have been a non-issue. It was also 1 shared cause for 3 test failures out of 12k tests that proved easy to fix.
I next tried removing our reliance on @ember/jquery to avoid its wrapping of xhr resolutions into the runloop. We rely on this because we set useFetch: false in all of our adapters. Notably: the default for EmberData has for all of 4.x been useFetch: true.
This resulted in dozens of test failures, possibly as many as a hundred. In debugging, it appears the reason for these failures is that tests that triggered async actions and ember-concurrency tasks were relying on the runloop initiated by jquery to count towards settledness. ember-concurrency itself makes widespread use of the runloop for most task related work. Combined, this means that await settled() and await render() and await click() and similar in tests capture a large body of async that might otherwise escape.
However, fixing this is as simple as ember-concurrency adding its own test waiters. EmberData already uses one, but there are some scenarios it intentionally does not cover (background requests). In these tests the cause was the request was being kicked off several promises deep from the triggering action and thus escaped the bounds of settled due to the missing EC waiter. The reason the jquery runloop usage papered over this was that it joined the next EC tick flush to the promise resolution in the test. Even if EC did not add a waiter, this is a class of issues that would not exist if we were to adopt the proposed RFC because the associated EmberData waiter would have been properly captured despite being multiple promises deep.
Current conclusions:
- I see no significant blocker to continuing to explore this RFC
- The biggest risk seems to be to tests not app code, and most prominently in locations where EC is in use
- We should shore up EC before shipping a new scheduler to avoid friction there
- apps using
useFetch: falseshould really stop doing so ;)
Additional design note: it might be a nice thing to wrap the functions passed to the on modifier in tests with a waiter if they return a promise. This could avoid a lot of test-waiter creation.
Feedback from RFC review discussion:
- let's add detail to "how we teach this" explaining exactly what is deprecated and how it should appear in the deprecation guide and what people should be told about replacements
- what's the experience in terms of when people will see deprecations, when should they flip the optional feature flag.
- what is the rollout timeline? Which deprecations until 6.0? 7.0?