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

Add postTask browser scheduler implementation #19479

Merged
merged 6 commits into from
Jul 29, 2020

Conversation

rickhanlonii
Copy link
Member

@rickhanlonii rickhanlonii commented Jul 29, 2020

Overview

This diff adds a Scheduler implementation that uses the experimental postTask API provided by Chrome.

Details

The postTask API is an experimental first step towards adding main thread scheduling to browsers.

It's based off of the main-thread-scheduling proposal and help solves the issue of coordinating work at various priorities. In React's case, it allows a browser-native strategy for breaking up long tasks (such as rendering) into smaller chucks that yield to other, possibly more important, work in between.

React already has a mechanism for breaking rendering into smaller chucks that yield to other work, and we use it in concurrent mode. The way we do that today is to use the MessageChannel API to "schedule" work:

let scheduledWork;

function doWork() {
  scheduledWork();
}

// Create a MessageChannel that we will post work to.
// the browser will call onmessage when it's our turn to work.
const channel = new MessageChannel();
const port = channel.port2;
channel.port1.onmessage = doWork;

// Entry point to scheduling work
export function scheduleWork(callback) {
  scheduledWork = callback;
  port.postMessage(null);
};

The change in this diff replaces the above strategy with postTask:

export function scheduleWork(callback) {
  scheduler.postTask(callback);
};

Why

There are a few disadvantages of the MessageChannel implementation.

First, all work is scheduled with the same priority. This initial change doesn't solve this because we're still posting all tasks with the same priority. In the future, the scheduler API will allow us to post tasks with different priorities levels and the browser will do the scheduling.

Second, the MessageChannel implementation requires us to do work in 5ms increments and yield to the browser to see if there's more browser work to do. In the future, this can be improved with additional scheduler APIs which will allow us to check if there is pending input. This will allow React to continue rendering until the browser has more important work today, and fill more gaps in under utilized CPU time.

Finally, the MessageChannel implementation does not have a way to continue work that's interrupted. This means, when rendering is paused to yield to the browser, we cannot continue until the event loops comes back around again and we will pay the overhead of letting other (lower-priority) task run in between. What we want to do is ask the browser to yield to higher priority work, but continue with our work before anything else that's the same priority or lower is allowed to complete. This will be possible with scheduler.yield.

For the first step though, we'll continue to manage priority in user land and yield to entire event loop every 5s.

@facebook-github-bot facebook-github-bot added CLA Signed React Core Team Opened by a member of the React Core Team labels Jul 29, 2020
@codesandbox-ci
Copy link

codesandbox-ci bot commented Jul 29, 2020

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 416ec1e:

Sandbox Source
React Configuration

@sizebot
Copy link

sizebot commented Jul 29, 2020

Details of bundled changes.

Comparing: 5227a37...416ec1e

scheduler

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
scheduler-unstable_post_task.development.js n/a n/a 0 B 19.81 KB 0 B 5.2 KB NODE_DEV
scheduler-tracing.development.js 0.0% -0.2% 8.8 KB 8.8 KB 1.78 KB 1.78 KB NODE_DEV
scheduler-unstable_mock.development.js 0.0% -0.0% 23.86 KB 23.86 KB 5.43 KB 5.43 KB UMD_DEV
scheduler-unstable_post_task.production.min.js n/a n/a 0 B 3.51 KB 0 B 1.51 KB NODE_PROD
scheduler-tracing.production.min.js 0.0% -0.6% 672 B 672 B 346 B 344 B NODE_PROD
Scheduler-dev.js -0.0% -0.0% 25.54 KB 25.54 KB 6.49 KB 6.49 KB FB_WWW_DEV
Scheduler-prod.js -0.0% -0.1% 12.31 KB 12.3 KB 3 KB 3 KB FB_WWW_PROD
Scheduler-profiling.js -0.0% -0.1% 17.12 KB 17.11 KB 3.9 KB 3.9 KB FB_WWW_PROFILING
Scheduler-dev.js -0.0% -0.0% 23.29 KB 23.29 KB 6 KB 6 KB RN_FB_DEV
Scheduler-prod.js -0.0% -0.1% 11.42 KB 11.41 KB 2.79 KB 2.78 KB RN_FB_PROD
Scheduler-profiling.js -0.0% -0.1% 15.24 KB 15.24 KB 3.58 KB 3.58 KB RN_FB_PROFILING
scheduler-unstable_mock.production.min.js 0.0% -0.1% 4.68 KB 4.68 KB 1.95 KB 1.95 KB UMD_PROD
scheduler-tracing.profiling.min.js 0.0% -0.3% 3.2 KB 3.2 KB 957 B 954 B NODE_PROFILING
SchedulerPostTask-dev.js -19.2% -18.1% 25.54 KB 20.63 KB 6.49 KB 5.31 KB FB_WWW_DEV
scheduler-unstable_mock.development.js 0.0% -0.0% 22.24 KB 22.24 KB 5.31 KB 5.31 KB NODE_DEV
SchedulerPostTask-prod.js -25.1% -23.4% 12.31 KB 9.21 KB 3 KB 2.3 KB FB_WWW_PROD
scheduler-unstable_mock.production.min.js 0.0% -0.2% 4.66 KB 4.66 KB 1.88 KB 1.88 KB NODE_PROD
SchedulerPostTask-profiling.js -18.3% -17.5% 17.12 KB 13.99 KB 3.9 KB 3.22 KB FB_WWW_PROFILING
scheduler.development.js -0.0% -0.1% 23.13 KB 23.12 KB 5.98 KB 5.98 KB NODE_DEV
scheduler.production.min.js -0.0% -0.3% 4.87 KB 4.87 KB 1.95 KB 1.94 KB NODE_PROD

Size changes (stable)

Generated by 🚫 dangerJS against 416ec1e

@sizebot
Copy link

sizebot commented Jul 29, 2020

Details of bundled changes.

Comparing: 5227a37...416ec1e

scheduler

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
scheduler-unstable_post_task.development.js n/a n/a 0 B 19.82 KB 0 B 5.21 KB NODE_DEV
scheduler-tracing.development.js 0.0% -0.1% 8.81 KB 8.81 KB 1.79 KB 1.79 KB NODE_DEV
scheduler-unstable_mock.development.js 0.0% -0.0% 23.88 KB 23.88 KB 5.44 KB 5.44 KB UMD_DEV
scheduler-unstable_post_task.production.min.js n/a n/a 0 B 3.52 KB 0 B 1.52 KB NODE_PROD
scheduler-tracing.production.min.js 0.0% -0.3% 685 B 685 B 354 B 353 B NODE_PROD
Scheduler-dev.js -0.0% -0.0% 25.54 KB 25.54 KB 6.49 KB 6.49 KB FB_WWW_DEV
Scheduler-prod.js -0.0% -0.1% 12.31 KB 12.3 KB 3 KB 3 KB FB_WWW_PROD
Scheduler-profiling.js -0.0% -0.1% 17.12 KB 17.11 KB 3.9 KB 3.9 KB FB_WWW_PROFILING
Scheduler-dev.js -0.0% -0.0% 23.29 KB 23.29 KB 6 KB 6 KB RN_FB_DEV
Scheduler-prod.js -0.0% -0.1% 11.42 KB 11.41 KB 2.79 KB 2.78 KB RN_FB_PROD
Scheduler-profiling.js -0.0% -0.1% 15.24 KB 15.24 KB 3.58 KB 3.58 KB RN_FB_PROFILING
scheduler-unstable_mock.production.min.js 0.0% -0.0% 4.7 KB 4.7 KB 1.96 KB 1.96 KB UMD_PROD
scheduler-tracing.profiling.min.js 0.0% -0.3% 3.21 KB 3.21 KB 965 B 962 B NODE_PROFILING
SchedulerPostTask-dev.js -19.2% -18.1% 25.54 KB 20.63 KB 6.49 KB 5.31 KB FB_WWW_DEV
SchedulerPostTask-prod.js -25.1% -23.4% 12.31 KB 9.21 KB 3 KB 2.3 KB FB_WWW_PROD
scheduler-unstable_mock.production.min.js 0.0% -0.1% 4.67 KB 4.67 KB 1.89 KB 1.89 KB NODE_PROD
SchedulerPostTask-profiling.js -18.3% -17.5% 17.12 KB 13.99 KB 3.9 KB 3.22 KB FB_WWW_PROFILING
scheduler.development.js -0.0% -0.0% 23.14 KB 23.14 KB 5.99 KB 5.99 KB NODE_DEV
scheduler.production.min.js -0.0% -0.2% 4.88 KB 4.88 KB 1.96 KB 1.95 KB NODE_PROD

Size changes (experimental)

Generated by 🚫 dangerJS against 416ec1e

@rickhanlonii rickhanlonii merged commit 7c8cc43 into facebook:master Jul 29, 2020
@rickhanlonii rickhanlonii deleted the rh-post-task-impl branch July 29, 2020 20:06
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.

5 participants