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

Land update lane priorities #20919

Closed
wants to merge 0 commits into from

Conversation

rickhanlonii
Copy link
Member

Overview

Depends on #20918

This change lands an experiment we ran to decouple the scheduler priority from React updates by creating an internal update priority that's tracked separately from the Scheduler.

Motivation

The original thinking was that users would control the priority of updates via the scheduler package, which would expose methods for controlling the priority of scheduled tasks. This made more sense at the beginning of the old expiration times model because an update priority roughly corresponded with the expiration time of that task, but as we've evolved our understanding or concurrent mode and moved to the lanes implementation, there's less of a 1-1 correspondence between task priority and update priority. It also made more sense based on certain implementations of a browser scheduler, which has not made it into the spec, making our model of how the scheduler would be used out of date.

Instead, we now expose functions directly from React to control the priority of React updates such as startTransition which de-prioritizes updates and flushSync which prioritizes updates. In practice, we've found that these two methods alone cover all of the use cases for needed for task prioritization, along with heuristics inside of React to decide when updates depend on each other or need rebased.

As an added benefit, this change also simplifies the layering between the scheduler and React because users or events can now directly change the update priority in React, instead of going around React to update the priority in the scheduler with React reading the scheduler priority in various critical paths. This makes the scheduler more of a prollyfill for native scheduling, with React and users using the scheduler simply as a mechanism to schedule tasks.

@facebook-github-bot facebook-github-bot added CLA Signed React Core Team Opened by a member of the React Core Team labels Mar 3, 2021
@sizebot
Copy link

sizebot commented Mar 3, 2021

Comparing: d745597...0388bba

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable/react-dom/cjs/react-dom.production.min.js = 123.31 kB 123.28 kB +0.08% 39.68 kB 39.71 kB
oss-experimental/react-dom/cjs/react-dom.production.min.js = 129.90 kB 129.81 kB +0.10% 41.70 kB 41.75 kB
facebook-www/ReactDOM-prod.classic.js = 414.59 kB 411.41 kB = 76.58 kB 76.25 kB
facebook-www/ReactDOM-prod.modern.js = 402.93 kB 399.75 kB = 74.69 kB 74.35 kB
facebook-www/ReactDOMForked-prod.classic.js = 414.60 kB 411.42 kB = 76.59 kB 76.24 kB

Significant size changes

Includes any change greater than 0.2%:

Expand to show
Name +/- Base Current +/- gzip Base gzip Current gzip
facebook-react-native/react-test-renderer/cjs/ReactTestRenderer-profiling.js +0.68% 254.01 kB 255.74 kB +0.57% 46.59 kB 46.85 kB
facebook-react-native/react-test-renderer/cjs/ReactTestRenderer-prod.js +0.57% 241.47 kB 242.86 kB +0.39% 44.34 kB 44.52 kB
react-native/implementations/ReactFabric-profiling.fb.js +0.56% 286.57 kB 288.18 kB +0.45% 51.38 kB 51.61 kB
react-native/implementations/ReactFabric-profiling.js +0.56% 286.63 kB 288.24 kB +0.45% 51.41 kB 51.64 kB
react-native/implementations/ReactNativeRenderer-profiling.fb.js +0.55% 293.73 kB 295.35 kB +0.45% 52.68 kB 52.92 kB
react-native/implementations/ReactNativeRenderer-profiling.js +0.55% 293.80 kB 295.41 kB +0.45% 52.71 kB 52.95 kB
react-native/implementations/ReactFabric-prod.fb.js +0.46% 273.90 kB 275.16 kB +0.33% 49.04 kB 49.20 kB
react-native/implementations/ReactFabric-prod.js +0.46% 273.95 kB 275.21 kB +0.33% 49.07 kB 49.23 kB
react-native/implementations/ReactNativeRenderer-prod.fb.js +0.45% 281.09 kB 282.35 kB +0.34% 50.37 kB 50.54 kB
react-native/implementations/ReactNativeRenderer-prod.js +0.45% 281.15 kB 282.41 kB +0.33% 50.40 kB 50.57 kB
facebook-www/ReactDOMTesting-prod.modern.js +0.33% 387.68 kB 388.95 kB +0.22% 73.56 kB 73.72 kB
facebook-www/ReactDOMTesting-prod.classic.js +0.32% 401.28 kB 402.56 kB +0.19% 75.82 kB 75.97 kB
facebook-www/JSXDEVRuntime-dev.classic.js = 42.15 kB 42.05 kB = 11.78 kB 11.76 kB
facebook-www/JSXDEVRuntime-dev.modern.js = 42.15 kB 42.05 kB = 11.78 kB 11.76 kB
facebook-www/ReactDOMForked-profiling.classic.js = 434.52 kB 432.44 kB = 80.07 kB 79.76 kB
facebook-www/ReactDOM-profiling.classic.js = 434.51 kB 432.43 kB = 80.07 kB 79.78 kB
facebook-www/ReactDOMForked-profiling.modern.js = 422.81 kB 420.73 kB = 78.23 kB 77.96 kB
facebook-www/ReactDOM-profiling.modern.js = 422.80 kB 420.72 kB = 78.22 kB 77.95 kB
facebook-www/ReactDOMForked-dev.classic.js = 1,072.21 kB 1,066.49 kB = 237.13 kB 236.46 kB
facebook-www/ReactDOM-dev.classic.js = 1,072.20 kB 1,066.48 kB = 237.38 kB 236.66 kB
facebook-www/ReactDOMForked-dev.modern.js = 1,045.95 kB 1,040.23 kB = 231.95 kB 231.30 kB
facebook-www/ReactDOM-dev.modern.js = 1,045.94 kB 1,040.22 kB = 232.21 kB 231.51 kB
facebook-www/ReactART-dev.classic.js = 714.51 kB 710.42 kB = 151.76 kB 151.31 kB
facebook-www/ReactART-dev.modern.js = 704.22 kB 700.13 kB = 149.67 kB 149.21 kB
facebook-www/ReactART-prod.classic.js = 267.92 kB 266.27 kB = 47.52 kB 47.32 kB
facebook-www/ReactART-prod.modern.js = 260.56 kB 258.91 kB = 46.24 kB 46.08 kB
facebook-www/ReactDOMForked-prod.classic.js = 414.60 kB 411.42 kB = 76.59 kB 76.24 kB
facebook-www/ReactDOM-prod.classic.js = 414.59 kB 411.41 kB = 76.58 kB 76.25 kB
facebook-www/ReactDOMForked-prod.modern.js = 402.94 kB 399.76 kB = 74.70 kB 74.36 kB
facebook-www/ReactDOM-prod.modern.js = 402.93 kB 399.75 kB = 74.69 kB 74.35 kB
facebook-www/SchedulerTracing-dev.classic.js = 11.40 kB 11.30 kB = 2.50 kB 2.48 kB
facebook-www/SchedulerTracing-dev.modern.js = 11.40 kB 11.29 kB = 2.50 kB 2.49 kB
facebook-www/ReactIs-dev.modern.js = 10.37 kB 10.27 kB = 2.77 kB 2.75 kB
facebook-www/ReactIs-dev.classic.js = 10.10 kB 10.00 kB = 2.73 kB 2.71 kB

Generated by 🚫 dangerJS against 0388bba

Copy link
Member Author

@rickhanlonii rickhanlonii left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One notable impact of this change is that anything that was reading Scheduler.getCurrentPriorityLevel expecting it to be the current update priority will be broken. With these changes, nothing internal should be impacted, but maybe some callers like www could.

@@ -1057,7 +1056,7 @@ function commitUnmount(
finishedRoot: FiberRoot,
current: Fiber,
nearestMountedAncestor: Fiber,
renderPriorityLevel: ReactPriorityLevel,
renderPriorityLevel: LanePriority,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switched all these methods to pass around a LanePriority now. After this, the only references to this type are in ReactFiberLanes (for converting between), SchedulerWithReactIntegration, and the DevTools.

const schedulerPriority =
priorityLevel === NoLanePriority
? NormalPriority
: lanePriorityToSchedulerPriority(priorityLevel);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DevTools is expecting the scheduler priority, so I'm converting to it here. I'm not sure what the plan should be for this - i.e should we update devtools to use the updateLanePriority instead of the scheduler priority? cc @bvaughn for interest

@@ -395,7 +392,7 @@ export function requestUpdateLane(fiber: Fiber): Lane {
if ((mode & BlockingMode) === NoMode) {
return (SyncLane: Lane);
} else if ((mode & ConcurrentMode) === NoMode) {
return getCurrentPriorityLevel() === ImmediateSchedulerPriority
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notable update here - now we can just check if the updateLanePriority is Sync, otherwise use batched.

@@ -486,7 +480,7 @@ function requestRetryLane(fiber: Fiber) {
if ((mode & BlockingMode) === NoMode) {
return (SyncLane: Lane);
} else if ((mode & ConcurrentMode) === NoMode) {
return getCurrentPriorityLevel() === ImmediateSchedulerPriority
return getCurrentUpdateLanePriority() === SyncLanePriority
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto here for the retry lane.

priorityLevel === ImmediateSchedulerPriority)
// Only updates greater than default considered discrete, even inside a discrete event.
higherLanePriority(updateLanePriority, DefaultLanePriority) !==
DefaultLanePriority
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another notable change - instead of checking the scheduler priority, check the update lane priority.

pendingPassiveEffectsRenderPriority =
renderPriorityLevel === NoLanePriority
? DefaultLanePriority
: renderPriorityLevel;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I switched this over to use the updateLanePriority. Plan is to remove this in a follow up.

Copy link
Collaborator

@acdlite acdlite left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this PR does more than land the experiment. Would you mind landing the new stuff in a separate step from the stuff that was already shipped? Don't need a PR, just land this one in two commits.

@rickhanlonii rickhanlonii force-pushed the rh-land-decouple branch 3 times, most recently from 9efed01 to 4e6de2a Compare March 8, 2021 17:52
@rickhanlonii rickhanlonii deleted the rh-land-decouple branch March 8, 2021 19:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed React Core Team Opened by a member of the React Core Team
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants