-
Notifications
You must be signed in to change notification settings - Fork 46.8k
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
Track "pending" and "suspended" ranges #16663
Conversation
A FiberRoot can have pending work at many distinct priorities. (Note: we refer to these levels as "expiration times" to distinguish the concept from Scheduler's notion of priority levels, which represent broad categories of work. React expiration times are more granualar. They're more like a concurrent thread ID, which also happens to correspond to a moment on a timeline. It's an overloaded concept and I'm handwaving over some of the details.) Given a root, there's no convenient way to read all the pending levels in the entire tree, i.e. there's no single queue-like structure that tracks all the levels, because that granularity of information is not needed by our algorithms. Instead we track the subset of information that we actually need — most importantly, the highest priority level that exists in the entire tree. Aside from that, the other information we track includes the range of pending levels that are known to be suspended, and therefore should not be worked on. This is a refactor of how that information is tracked, and what each field represents: - A *pending* level is work that is unfinished, or not yet committed. This includes work that is suspended from committing. `firstPendingTime` and `lastPendingTime` represent the range of pending work. (Previously, "pending" was the same as "not suspended.") - A *suspended* level is work that did not complete because data was missing. `firstSuspendedTime` and `lastSuspendedTime` represent the range of suspended work. It is a subset of the pending range. (These fields are new to this commit.) - `nextAfterSuspendedTime` represents the next known level that comes after the suspended range. This commit doesn't change much in terms of observable behavior. The one change is that, when a level is suspended, React will continue working on the next known level instead of jumping straight to the last pending level. Subsequent commits will use this new structure for a more substantial refactor for how tasks are scheduled per root.
ReactDOM: size: 0.0%, gzip: 0.0% Details of bundled changes.Comparing: 9ce8711...100945b react-dom
react-art
react-native-renderer
react-test-renderer
react-reconciler
|
37c942e
to
5d1fe07
Compare
return ( | ||
firstSuspendedTime !== NoWork && | ||
(firstSuspendedTime >= expirationTime && | ||
lastSuspendedTime <= expirationTime) |
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.
FYI, totally I think it's time to rename the name 'expirationTime' because it's been talked/discussed a few months, but for now, since it's a 'time' could we compare them through the 'time order'? I.e. from small to large (lastSuspendedTime <= expirationTime && expirationTime <= firstSuspendedTime
)
5d1fe07
to
100945b
Compare
if (lastPendingTime < expirationTime) { | ||
// There's lower priority work. It might be unsuspended. Try rendering | ||
// at that level immediately, while preserving the position in the queue. | ||
return renderRoot.bind(null, root, lastPendingTime); |
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.
We're discussing this. Seems like this refactoring changed things.
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.
This can be replaced by a prepareFreshStack in an update that happens during a yield.
If the current tree has already determined that it has remaining work at lower pri, we can use that info to eagerly throw to terminate the render and try at lower pri.
// as well start doing that eagerly. | ||
// just going to try to recover at the pending time anyway so we might as | ||
// well start doing that eagerly. | ||
// | ||
// Ideally we should be able to do this even for retries but we don't yet | ||
// know if we're going to process an update which wants to commit earlier, | ||
// and this path happens very early so it would happen too often. Instead, | ||
// for that case, we'll wait until we complete. | ||
if (workInProgressRootHasPendingPing) { | ||
// We have a ping at this expiration. Let's restart to see if we get unblocked. | ||
prepareFreshStack(root, expirationTime); |
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.
This can be removed (maybe) because there exists one in the ping function already.
Closed by ab4951f |
A FiberRoot can have pending work at many distinct priorities. (Note: we refer to these levels as "expiration times" to distinguish the concept from Scheduler's notion of priority levels, which represent broad categories of work. React expiration times are more granular. They're more like a concurrent thread ID, which also happens to correspond to a moment on a timeline. It's an overloaded concept and I'm handwaving over some of the details.)
Given a root, there's no convenient way to read all the pending levels in the entire tree, i.e. there's no single queue-like structure that tracks all the levels, because that granularity of information is not needed by our algorithms. Instead we track the subset of information that we actually need — most importantly, the highest priority level that exists in the entire tree.
Aside from that, the other information we track includes the range of pending levels that are known to be suspended, and therefore should not be worked on.
This is a refactor of how that information is tracked, and what each field represents:
firstPendingTime
andlastPendingTime
represent the range of pending work. (Previously, "pending" was the same as "not suspended.")firstSuspendedTime
andlastSuspendedTime
represent the range of suspended work. It is a subset of the pending range. (These fields are new to this commit.)nextAfterSuspendedTime
represents the next known level that comes after the suspended range.This commit doesn't change much in terms of observable behavior. The one change is that, when a level is suspended, React will continue working on the next known level instead of jumping straight to the last pending level. Subsequent commits will use this new structure for a more substantial refactor for how tasks are scheduled per root.