mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
[Scheduler] Yield less if there's no pending input (#15959)
At the end of each frame, Scheduler yields control of the main thread so the browser can execute important tasks; most importantly, painting the screen and responding to user input. There's some overhead involved in regaining control of the main thread, so we'd like to yield as infrequently as possible to keep the UI responsive. The reason we yield on every frame is because there's no way for us to know whether we're blocking user input. `isInputPending` is an experimental browser API that gives us this information. It tells us whether there's a pending user input, which also means it tells us if there's *not* a pending user input. We can use this signal to decide whether it's OK not to yield. There's a max frame length after which we'll yield regardless, as a precaution against blocking non-input tasks that we don't know about.
This commit is contained in:
@@ -160,8 +160,38 @@ if (
|
||||
let activeFrameTime = 33;
|
||||
let fpsLocked = false;
|
||||
|
||||
// TODO: Make this configurable
|
||||
// TODO: Adjust this based on priority?
|
||||
let maxFrameLength = 300;
|
||||
|
||||
const isInputPending =
|
||||
navigator !== undefined &&
|
||||
navigator.scheduling !== undefined &&
|
||||
navigator.scheduling.isInputPending !== undefined
|
||||
? navigator.scheduling.isInputPending
|
||||
: null;
|
||||
|
||||
shouldYieldToHost = function() {
|
||||
return frameDeadline <= getCurrentTime();
|
||||
const currentTime = getCurrentTime();
|
||||
if (currentTime < frameDeadline) {
|
||||
// There's still time left in the frame.
|
||||
return false;
|
||||
} else {
|
||||
// There's no time left in the frame. We may want to yield control of the
|
||||
// main thread, so the browser can perform high priority tasks. The main
|
||||
// ones are painting and user input. If we're certain there's no user
|
||||
// input, then we can yield less often without making the app less
|
||||
// responsive. We'll eventually yield regardless, since there could be
|
||||
// other main thread tasks that we don't know about.
|
||||
if (isInputPending !== null && !isInputPending()) {
|
||||
// There's no pending input. Only yield if we've reached the max
|
||||
// frame length.
|
||||
return currentTime >= frameDeadline + maxFrameLength;
|
||||
}
|
||||
// Either there is pending input, or there's no way for us to be sure
|
||||
// because `isInputPending` is not available.
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
forceFrameRate = function(fps) {
|
||||
|
||||
Reference in New Issue
Block a user