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

[scheduler] Yield many times per frame, no rAF #16214

Merged
merged 1 commit into from
Jul 26, 2019

Conversation

acdlite
Copy link
Collaborator

@acdlite acdlite commented Jul 25, 2019

Adds experimental flag to yield many times per frame using a message event loop, instead of the current approach of guessing the next vsync and yielding at the end of the frame.

This new approach forgoes a requestAnimationFrame entirely. It posts a message event and performs a small amount of work (5ms) before yielding to the browser, regardless of where it might be in the vsync cycle. At the end of the event, if there's work left over, it posts another message event.

This should keep the main thread responsive even for really high frame rates. It also shouldn't matter if the hardware frame rate changes after page load (our current heuristic only detects if the frame rate increases, not decreases).

The main risk is that yielding more often will exacerbate main thread contention with other browser tasks.

I'm also not sure to what extent message events are throttled when the tab is backgrounded, relative to requestAnimationFrame or setTimeout. I'm starting with the assumption that message events fire with at least the same priority as timers, but I'll need to confirm.

Let's try it and see.

Adds experimental flag to yield many times per frame using a message
event loop, instead of the current approach of guessing the next vsync
and yielding at the end of the frame.

This new approach forgoes a `requestAnimationFrame` entirely. It posts a
message event and performs a small amount of work (5ms) before yielding
to the browser, regardless of where it might be in the vsync cycle. At
the end of the event, if there's work left over, it posts another
message event.

This should keep the main thread responsive even for really high frame
rates. It also shouldn't matter if the hardware frame rate changes after
page load (our current heuristic only detects if the frame rate
increases, not decreases).

The main risk is that yielding more often will exacerbate main thread
contention with other browser tasks.

Let's try it and see.
@sizebot
Copy link

sizebot commented Jul 25, 2019

React: size: 0.0%, gzip: -0.0%

Details of bundled changes.

Comparing: c0830a0...5b706be

react

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react.development.js +1.6% +1.1% 115.09 KB 116.91 KB 29.01 KB 29.33 KB UMD_DEV
react.production.min.js 0.0% -0.0% 13.03 KB 13.03 KB 5.08 KB 5.07 KB UMD_PROD
react.profiling.min.js 0.0% 0.0% 15.23 KB 15.23 KB 5.61 KB 5.61 KB UMD_PROFILING
react.production.min.js 0.0% 0.0% 6.68 KB 6.68 KB 2.75 KB 2.75 KB NODE_PROD

scheduler

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
SchedulerMock-dev.js +0.4% +0.5% 21.28 KB 21.36 KB 4.64 KB 4.66 KB FB_WWW_DEV
scheduler.development.js +6.5% +4.4% 28.14 KB 29.96 KB 7.03 KB 7.35 KB NODE_DEV
Scheduler-dev.js +6.8% +4.6% 28.84 KB 30.79 KB 7.15 KB 7.48 KB FB_WWW_DEV
Scheduler-prod.js 🔺+4.4% 🔺+3.3% 17.17 KB 17.92 KB 3.59 KB 3.7 KB FB_WWW_PROD
scheduler-tracing.production.min.js 0.0% 🔺+0.3% 728 B 728 B 381 B 382 B NODE_PROD
scheduler-unstable_mock.development.js 0.0% 0.0% 20.8 KB 20.8 KB 4.56 KB 4.56 KB UMD_DEV
scheduler-tracing.profiling.min.js 0.0% +0.1% 3.26 KB 3.26 KB 998 B 999 B NODE_PROFILING
scheduler-unstable_mock.production.min.js 0.0% -0.1% 5.07 KB 5.07 KB 1.94 KB 1.94 KB NODE_PROD

Generated by 🚫 dangerJS

@acdlite acdlite force-pushed the scheduler-message-loop branch 2 times, most recently from 7cc5b84 to 5b706be Compare July 26, 2019 00:15
@acdlite acdlite merged commit 75ab53b into facebook:master Jul 26, 2019
@yisar
Copy link
Contributor

yisar commented Oct 4, 2019

Why not use setTimeOut 0 directly? What the difference between setTimeOut and Message Channel?

This was referenced Oct 5, 2019
@SyMind
Copy link

SyMind commented Oct 22, 2020

Promise polyfill was originally used in React, why not use Promise? Now queueMicroTask is living standard, why not use it?

@jddxf
Copy link
Contributor

jddxf commented Nov 10, 2020

@SyMind Microtasks are continuously executed until the microtask queue on the event loop is empty which means a higher-pri task such as one for user interaction would be blocked by React.

@franckchen
Copy link

Why not use setTimeOut 0 directly? What the difference between setTimeOut and Message Channel?

We prefer MessageChannel because of the 4ms setTimeout clamping

@beMySun
Copy link

beMySun commented May 31, 2022

Why not use setTimeOut 0 directly? What the difference between setTimeOut and Message Channel?

We prefer MessageChannel because of the 4ms setTimeout clamping

https://github.com/facebook/react/releases/tag/v16.10.0

@lizuncong
Copy link

Why not use setTimeOut 0 directly? What the difference between setTimeOut and Message Channel?

We prefer MessageChannel because of the 4ms setTimeout clamping

https://github.com/facebook/react/releases/tag/v16.10.0

I have discussed which APIs are suitable for task scheduling:lizuncong/mini-react#22

@beMySun
Copy link

beMySun commented Sep 12, 2022 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.