-
Notifications
You must be signed in to change notification settings - Fork 47.4k
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
[Fiber] Change work priority to represent the priority of the child #8716
Conversation
9b47df1
to
0083655
Compare
Got it mostly working! Just one remaining issue with reusing side-effects on an already completed subtree. I'll look at this tomorrow. |
0083655
to
8b61e5b
Compare
@sebmarkbage This is now ready for review. (Well, if/when #8655 is approved, I mean.) |
@@ -831,9 +831,9 @@ describe('ReactIncrementalSideEffects', () => { | |||
// Updated. | |||
span(1), | |||
div( | |||
span(1), |
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.
I think this change is correct. The effect is flushed sooner than before because we're reusing more work. I may be wrong.
if (fiber.tag === HostRoot) { | ||
// This is a root, which does not have a parent, so we need to use the | ||
// update queue. | ||
addTopLevelUpdate(fiber, { element: null }, null, TaskPriority); |
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 feels a bit weird but I couldn't think of a better solution.
Huh don't know why CircleCI is failing |
I think you forgot to re-record tests. The file says this is still failing: +src/renderers/shared/fiber/__tests__/ReactIncrementalSideEffects-test.js
+* can defer side-effects and reuse them later - complex But apparently you fixed it. |
What's weird is the file is correct locally, not on GH. Probably some stupid mistake I made. I'll check in a bit. |
Wrong branch? |
8b61e5b
to
0c240f4
Compare
7087d18
to
beaf215
Compare
Implications: - When we clone from current, set the pendingWorkPriority of the parent, not the child. - The check to bail out on low priority must occur earlier, before we beginWork on it. It turns out this only happens when the parent bails out on already finished work. So we do the check there.
Workaround for the fact that host roots (which act as an error boundary for uncaught errors) do not have a parent. Because the child will be set to null on the next commit, anyway, I think this is fine.
addf451
to
fb01f28
Compare
Must bubble up priority from a progressed subtree that was preempted by a high priority update. We know this is the case if the progressed priority is lower than the priority at which we're reconciling.
Without the change, the second update does not create higher priority work than the first one.
If we already completed a subtree, we should be able to bail out because the tree no longer has any priority.
I added this line in a previous diff because I was thought it was necessary to avoid dropping work. But it turns out that not only is it unnecessary, but it prevents us from being able to reuse already completed progressed work, because the bailout on low priority check will always fail.
This was causing effects to be dropped.
We now do this inside the scheduler, in performUnitOfWork
Neglected to do this in a previous commit. We keep these functions separate so that we don't have to perform the failed work check on every unit of work. Not sure if there's test we can write to ensure they stay in sync.
Fixes a bug, and reverts some of the changes I made in previous commits that was masking this incorrect behavior. I understand it better now. I'll rebase to clean this up. The demo is almost working but there are a few remaining bugs. Still investigating...
7b70d5f
to
2ce2a4b
Compare
I introduce the ReactDOMFrameScheduling module which just exposes rIC and rAF. The polyfill works by scheduling a requestAnimationFrame, store the time for the start of the frame, then schedule a postMessage which gets scheduled after paint. The deadline is set to time + frame rate. By separating the idle call into a separate event tick we ensure that layout, paint and other browser work is counted against the available time. The frame rate is dynamically adjusted by tracking the minimum time between two rAF callbacks. This is not perfect because browsers can schedule multiple callbacks to catch up after a long frame. To compensate for this we only adjust if two consecutive periods are faster than normal. This seems to guarantee that we will hit frame deadlines and we don't end up dropping frames. However, there is still some lost time so we risk starving by not having enough idle time. Especially Firefox seems to have issues keeping up on the triangle demo However, that is also true for native rIC in Firefox. It seems like more render work is scheduled on the main thread pipeline and also that JS execution just generally has more overhead.
Not sure why I did it this way before, but it's a mistake.
Almost have everything working. There's still a bug in the demo that needs to be fixed (probably not introduced by this PR because it exists in Once I figure that remaining bit out I'll write more tests related to reusing child effects, since that's crucial to the demo working properly but there are many cases that aren't covered by tests. |
frameDeadline = rafTime + activeFrameTime; | ||
if (!isIdleScheduled) { | ||
isIdleScheduled = true; | ||
window.postMessage(messageKey, '*'); |
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.
Is it safe to assume this module isn’t relevant for server rendering?
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.
Fiber DOM renderer is client-only so no, it's not relevant.
Can we close this? |
findNextUnitOfWork
, we need to check both the update priority and the work priority of the root, since the work priority field no longer represents both.scheduleUpdate
, when bubbling the priority to the root, skip the fiber that is being updated on and start with the parent.resetWorkPriority
fromcommitAllWork
in the scheduler intoReactFiberCompleteWork
so we can branch on the type of the component. This is needed for HostComponents, which may have leftover work priority if we bailed out on a hidden subtree.beginWork
. Instead we have to perform that check while performing work on the parent, before its child is returned.