-
Notifications
You must be signed in to change notification settings - Fork 47k
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
[RFC] Schedule supports two priorities #12707
Conversation
**what is the change?:** We want to support calling ReactScheduler multiple times with different callbacks, even if the initial callback hasn't been called yet. There are two possible ways ReactScheduler can handle multiple callbacks, and in one case we know that callbackA depends on callbackB having been called already. For example; callbackA -> updates SelectionState in a textArea callbackB -> processes the deletion of the text currently selected. We want to ensure that callbackA happens before callbackB. For now we will flush callbackB as soon as callbackA is added. In the next commit we'll split this into two methods, which support two different behaviors here. We will support the usual behavior, which would defer both callbackA and callbackB. One issue with this is that we now create a new object to pass to the callback for every use of the scheduler, while before we reused the same object and mutated the 'didExpire' before passing it to each new callback. With multiple callbacks, I think this leads to a risk of mutating the object which is being used by multiple callbacks. **why make this change?:** We want to use this scheduling helper to coordinate between React and non-React scripts. **test plan:** Added and ran a unit test.
**what is the change?:** We added support for serial scheduled callbacks to schedule more callbacks, and maintained the order of first-in first-called. **why make this change?:** This is sort of a corner case, but it's totally possible and we do something similar in React. We wouldn't do this with serial callbacks, but with deferred callbacks we do a pattern like this: ``` + + | +--------------------+ +----------------+ | +--------------------------------+ +-------------------------+ | | | | | | | | | | | | main thread blocked| |callback A runs | | | main thread blocked again | |callback A runs again, finishes | +--------------------+ +-----+----------+ | +--------------------------------+ ++------------------------+ v ^ v ^ schedule +------------------------->+ no time left!+----------------------->+ callbackA reschedule | callbackA + to do more work later. ``` **test plan:** Wrote some fun new tests and ran them~ Also ran existing React unit tests. As of this PR they are still directly using this module. Rename ReactScheduler.rIC -> scheduleSerialCallback **what is the change?:** We renamed this method. **why make this change?:** 1) This is no longer just a polyfill for requestIdleCallback. It's becoming something of it's own. 2) We are about to introduce a second variant of behavior for handling scheduling of callbacks, so want to have names which make sense for differentiating the two priorities. **test plan:** Ran tests
**what is the change?:** Rename a method and add tests **why make this change?:** This will set things up for adding a new method which cancels callbacks which have 'deferred' priority. **test plan:** Run the updated tests.
**what is the change?:** see title **why make this change?:** For more readable and organized test and test output. I put this in it's own commit because the diff looks gnarly, but we're just moving things around. No actual changes. **test plan:** Run the tests
**what is the change?:** Add support for multiple priorities. - We are storing pending deferred callbacks in an array for simplicity, which means that we have to do a linear search of the array repeatedly to find callbacks which are past their timeout. It would be more efficient to use a min heap to store them and then quickly find the expired ones, but I'm not sure it's worth the extra complexity unless we know that we'll be dealing with a high number of pending deferred callbacks at once. If there are a high number of pending deferred callbacks, we have other problems to consider. Also the implementation of cancel is missing and I haven't added support for returning ids which can be used to cancel. Not sure we need this yet, but will have to add it eventually. **why make this change?:** To get feedback on this approach as early as possible. **test plan:** Tests are a challenge. To write a unit test I'll need to add support for injecting some of the browser APIs as dependencies, and basically allow us to create a noopScheduler. We also should have a real browser fixture to test this. Going to work on that in another branch. **issue:** Internal task T28128480
@@ -41,16 +41,210 @@ describe('ReactScheduler', () => { | |||
ReactScheduler = require('react-scheduler'); | |||
}); | |||
|
|||
it('rIC calls the callback within the frame when not blocked', () => { | |||
const {rIC} = ReactScheduler; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like lots was rewritten but really I just wrapped the existing tests in a new 'describe' block. Would separate this into a different PR ideally.
The only real change is that new tests were added at the end.
ReactDOM: size: 🔺+0.6%, gzip: 🔺+0.8% Details of bundled changes.Comparing: 9c77ffb...a13a126 react-dom
react-art
react-scheduler
Generated by 🚫 dangerJS |
We re-architected the commits this depends on, will open a new PR once I get this far again. See #12682 |
This depends on #12682 which still needs review, but I wanted to keep pushing forward so submitting this anyway.
Would love early feedback on this, and for now I'll shift to working on test coverage, which is the last significant piece.
To write the unit and fixture test coverage for this new complex behavior, we need to allow configuring 'schedule' with dependency injection. Something like this - pseudocode - :