-
Notifications
You must be signed in to change notification settings - Fork 46.9k
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
Rewrite ReactFiberScheduler for better integration with Scheduler package #15151
Conversation
Is it expected that React's size goes up by 1.4% gzip? :o I thought with these changes it would have gone down. Maybe missing some DEV wrappers? |
@trueadm All the changes I've made in this PR are in a forked file that isn't enabled yet (except via |
Once this PR is ready, I would expect ReactDOM's size to go slightly down, or at least stay even. Scheduler might go up a bit if I end up lifting stuff into that package. React isomorphic package shouldn't be affected at all. |
50b7091
to
2d7a6ac
Compare
fc0d30e
to
f007ae7
Compare
ReactDOM: size: 🔺+0.2%, gzip: 🔺+0.3% Details of bundled changes.Comparing: aed0e1c...f1dc626 react-dom
react-art
react-native-renderer
react-test-renderer
react-reconciler
Generated by 🚫 dangerJS |
d739dca
to
2f60c47
Compare
396abed
to
3b89f99
Compare
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.
The bundle size is up. What's that about?
packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js
Show resolved
Hide resolved
packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js
Outdated
Show resolved
Hide resolved
packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js
Outdated
Show resolved
Hide resolved
@@ -1352,6 +1354,9 @@ describe('Profiler', () => { | |||
}, | |||
); | |||
}).toThrow('Expected error onWorkScheduled'); | |||
if (enableNewScheduler) { | |||
expect(Scheduler).toFlushAndYield(['Component:fail']); |
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.
What's happening here?
Re: bundle size, I think it might be the |
Adds a new implementation of ReactFiberScheduler behind a feature flag. We will maintain both implementations in parallel until the new one is proven stable enough to replace the old one. The main difference between the implementations is that the new one is integrated with the Scheduler package's priority levels.
Some fields only used by the old scheduler, and some by the new.
If synchronous updates are scheduled by a passive effect, that work should be flushed synchronously, even if flushPassiveEffects is called inside batchedUpdates.
React doesn't need this anyway because it never schedules callbacks if it's already rendering.
Turns out this isn't neccessary.
Should initialize to nothing, then assign the exports conditionally, instead of initializing to the old exports and then reassigning to the new ones.
Instead of wrapping in enableNewScheduler flag.
…kage (#15151) * Rewrite ReactFiberScheduler Adds a new implementation of ReactFiberScheduler behind a feature flag. We will maintain both implementations in parallel until the new one is proven stable enough to replace the old one. The main difference between the implementations is that the new one is integrated with the Scheduler package's priority levels. * Conditionally add fields to FiberRoot Some fields only used by the old scheduler, and some by the new. * Add separate build that enables new scheduler * Re-enable skipped test If synchronous updates are scheduled by a passive effect, that work should be flushed synchronously, even if flushPassiveEffects is called inside batchedUpdates. * Passive effects have same priority as render * Revert ability to cancel the current callback React doesn't need this anyway because it never schedules callbacks if it's already rendering. * Revert change to FiberDebugPerf Turns out this isn't neccessary. * Fix ReactFiberScheduler dead code elimination Should initialize to nothing, then assign the exports conditionally, instead of initializing to the old exports and then reassigning to the new ones. * Don't yield before commit during sync error retry * Call Scheduler.flushAll unconditionally in tests Instead of wrapping in enableNewScheduler flag.
We replay errors so you can break on paused exceptions. This is done in the second pass so that the first pass can ignore suspense. Originally this threw the original error. For suppression purposes we copied the flag onto the original error. https://github.com/facebook/react/blob/f1dc626b29b8bf0f14c75a8525e8650b7ea94a47/packages/react-reconciler/src/ReactFiberScheduler.old.js#L367-L369 During this refactor it changed to just throw the retried error: facebook#15151 We're not sure exactly why but it was likely just an optimization or clean up. So we can go back to throwing the original error. That helps in the case where a memoized function is naively not rethrowing each time such as in Node's module system.
We replay errors so you can break on paused exceptions. This is done in the second pass so that the first pass can ignore suspense. Originally this threw the original error. For suppression purposes we copied the flag onto the original error. https://github.com/facebook/react/blob/f1dc626b29b8bf0f14c75a8525e8650b7ea94a47/packages/react-reconciler/src/ReactFiberScheduler.old.js#L367-L369 During this refactor it changed to just throw the retried error: facebook#15151 We're not sure exactly why but it was likely just an optimization or clean up. So we can go back to throwing the original error. That helps in the case where a memoized function is naively not rethrowing each time such as in Node's module system. Unfortunately this doesn't fix the problem fully. Because invokeGuardedCallback captures the error and logs it to the browser. So you still end up seeing the wrong message in the logs. This just fixes so that the error boundary sees the first one.
We replay errors so you can break on paused exceptions. This is done in the second pass so that the first pass can ignore suspense. Originally this threw the original error. For suppression purposes we copied the flag onto the original error. https://github.com/facebook/react/blob/f1dc626b29b8bf0f14c75a8525e8650b7ea94a47/packages/react-reconciler/src/ReactFiberScheduler.old.js#L367-L369 During this refactor it changed to just throw the retried error: #15151 We're not sure exactly why but it was likely just an optimization or clean up. So we can go back to throwing the original error. That helps in the case where a memoized function is naively not rethrowing each time such as in Node's module system. Unfortunately this doesn't fix the problem fully. Because invokeGuardedCallback captures the error and logs it to the browser. So you still end up seeing the wrong message in the logs. This just fixes so that the error boundary sees the first one.
We replay errors so you can break on paused exceptions. This is done in the second pass so that the first pass can ignore suspense. Originally this threw the original error. For suppression purposes we copied the flag onto the original error. https://github.com/facebook/react/blob/f1dc626b29b8bf0f14c75a8525e8650b7ea94a47/packages/react-reconciler/src/ReactFiberScheduler.old.js#L367-L369 During this refactor it changed to just throw the retried error: facebook#15151 We're not sure exactly why but it was likely just an optimization or clean up. So we can go back to throwing the original error. That helps in the case where a memoized function is naively not rethrowing each time such as in Node's module system. Unfortunately this doesn't fix the problem fully. Because invokeGuardedCallback captures the error and logs it to the browser. So you still end up seeing the wrong message in the logs. This just fixes so that the error boundary sees the first one.
Pushing this early so I won't lose my work if my computer combusts.
I'm not going to bother with splitting this into chunks until I get most/all of the tests passing. Then I'll work on getting it into a reviewable state. (It'll probably be hard to review regardless, though, given the nature of the PR.)
Intentional semantic differences
In the old implementation, in sync mode, retrying a previously suspended tree is synchronous inside the promise resolution callback. The new implementation schedules an async callback to perform the retry. If multiple promise resolutions occur before the async callback fires, they will be batched together.
Todo
invokeGuardedCallback
ReactDOM.createBatch