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

[Umbrella] New algorithm for resuming interrupted work #11566

Open
acdlite opened this issue Nov 15, 2017 · 1 comment
Open

[Umbrella] New algorithm for resuming interrupted work #11566

acdlite opened this issue Nov 15, 2017 · 1 comment
Labels
Component: Reconciler React Core Team Opened by a member of the React Core Team Type: Umbrella

Comments

@acdlite
Copy link
Collaborator

acdlite commented Nov 15, 2017

Resuming is the ability to re-use fibers after they are interrupted by a higher-priority update. Take the following scenario: A component is updated at a normal, async priority. Before the update is finished processing, a higher-priority update is scheduled (let's say it's synchronous, though it could also be a higher-priority async update). The sync update interrupts the async update, leaving it unfinished. After the sync update finishes, we go back to processing the interrupted, async update. It's possible, and even likely, that the interrupted work wasn't touched by the sync work and can be resumed without starting over completely.

This is an important optimization for several async features we have in mind, including error handling, blockers, pre-rendering, and hidden priority.

We used to have an implementation of resuming that mostly worked but had some bugs. A few months ago, I spent some time identifying the bugs using fuzz testing and fixing them by iterating on the existing algorithm. I eventually got a version working that passed all the tests. But even this version didn't have all of the features we wanted, and the algorithm seemed inherently flawed. So we decided it would be best to scrap the existing algorithm and revisit resuming in the future.

We now believe we have a better idea of how resuming should work. I'm going to split the work into multiple PRs, and use this issue to keep track of our progress.

My apologies if some of my descriptions are hard to follow. It can be difficult to describe without resorting to jargon. I'll iterate on this issue as I work.

Always reconcile against current child set (#11564)

This is a small refactor that reflects what we already do without resuming: the set we reconcile against is always the current set. In the reverted resuming algorithm, the set we reconcile against was sometimes a work-in-progress set, and there are a few code paths that are left over from that implementation.

Stash interrupted children

When cloning a work-in-progress fiber from current, and there is already an existing work-in-progress that was interrupted, stash the interrupted work-in-progress children (and corresponding fields) in case we can reuse them later. In begin phase, add an additional check to see if incoming props/state match the interrupted props/state. If so, bail out and re-use the interrupted children. If not, the interrupted children are no longer useful, because we're about to re-render the parent and overwrite them. (Unmounted fibers actually can be re-used even if we re-render the parent; see next step.)

This gets us back to the same functionality we had in the old resuming algorithm. We can now resume interrupted children if we come back to it at the same priority at which it was originally rendered. The main limitation is that the work is lost if the parent is re-rendered at a higher priority.

*Need a way to distinguish between a work-in-progress fiber and the "previous current" fiber

Pool unmounted, interrupted children so they can resume even if parent re-renders at higher priority

When a fiber is about to be re-rendered, and there are interrupted children that could not be reused, search through the interrupted children and find the ones that are unmounted (don't have an alternate). Stash the unmounted children in a separate set; they can be kept around indefinitely without being overwritten. This set acts like a pool of children. The next time the parent is re-rendered at the priority of the interrupted children, check the pool for matches before creating new fibers.

@iamstarkov
Copy link

im digging through opened umbrella issues and this one is seems a little bit outdated. perhaps it should be merged into some other more relevant issue?

@necolas necolas added the React Core Team Opened by a member of the React Core Team label Jan 8, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Component: Reconciler React Core Team Opened by a member of the React Core Team Type: Umbrella
Projects
None yet
Development

No branches or pull requests

4 participants