-
Notifications
You must be signed in to change notification settings - Fork 47k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Work-in-progress] Assign expiration times to updates
An expiration time represents a time in the future by which an update should flush. The priority of the update is related to the difference between the current clock time and the expiration time. This has the effect of increasing the priority of updates as time progresses, to prevent starvation. This lays the initial groundwork for expiration times without changing any behavior. Future commits will replace work priority with expiration times.
- Loading branch information
Showing
12 changed files
with
251 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
/** | ||
* Copyright 2013-present, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the BSD-style license found in the | ||
* LICENSE file in the root directory of this source tree. An additional grant | ||
* of patent rights can be found in the PATENTS file in the same directory. | ||
* | ||
* @providesModule ReactFiberExpirationTime | ||
* @flow | ||
*/ | ||
|
||
'use strict'; | ||
|
||
import type {PriorityLevel} from 'ReactPriorityLevel'; | ||
const { | ||
NoWork, | ||
SynchronousPriority, | ||
TaskPriority, | ||
HighPriority, | ||
LowPriority, | ||
OffscreenPriority, | ||
} = require('ReactPriorityLevel'); | ||
|
||
const invariant = require('fbjs/lib/invariant'); | ||
|
||
// TODO: Use an opaque type once ESLint et al support the syntax | ||
export type ExpirationTime = number; | ||
|
||
const Done = 0; | ||
exports.Done = Done; | ||
|
||
const Never = Infinity; | ||
exports.Never = Infinity; | ||
|
||
// 1 unit of expiration time represents 10ms. | ||
function msToExpirationTime(ms: number): ExpirationTime { | ||
// Always add 1 so that we don't clash with the magic number for Done. | ||
return Math.round(ms / 10) + 1; | ||
} | ||
exports.msToExpirationTime = msToExpirationTime; | ||
|
||
function expirationTimeToMs(expirationTime: ExpirationTime): number { | ||
return (expirationTime - 1) * 10; | ||
} | ||
|
||
function ceiling(time: ExpirationTime, precision: number): ExpirationTime { | ||
return Math.ceil(Math.ceil(time * precision) / precision); | ||
} | ||
|
||
// Given the current clock time and a priority level, returns an expiration time | ||
// that represents a point in the future by which some work should complete. | ||
// The lower the priority, the further out the expiration time. We use rounding | ||
// to batch like updates together. The further out the expiration time, the | ||
// more we want to batch, so we use a larger precision when rounding. | ||
function priorityToExpirationTime( | ||
currentTime: ExpirationTime, | ||
priorityLevel: PriorityLevel, | ||
): ExpirationTime { | ||
switch (priorityLevel) { | ||
case NoWork: | ||
return Done; | ||
case SynchronousPriority: | ||
// Return a number lower than the current time, but higher than Done. | ||
return 1; | ||
case TaskPriority: | ||
// Return the current time, so that this work completes in this batch. | ||
return currentTime; | ||
case HighPriority: | ||
// Should complete within ~100ms. 120ms max. | ||
return msToExpirationTime(ceiling(100, 20)); | ||
case LowPriority: | ||
// Should complete within ~1000ms. 1200ms max. | ||
return msToExpirationTime(ceiling(1000, 200)); | ||
case OffscreenPriority: | ||
return Never; | ||
default: | ||
invariant( | ||
false, | ||
'Switch statement should be exhuastive. ' + | ||
'This error is likely caused by a bug in React. Please file an issue.', | ||
); | ||
} | ||
} | ||
exports.priorityToExpirationTime = priorityToExpirationTime; | ||
|
||
// Given the current clock time and an expiration time, returns the | ||
// corresponding priority level. The more time has advanced, the higher the | ||
// priority level. | ||
function expirationTimeToPriorityLevel( | ||
currentTime: ExpirationTime, | ||
expirationTime: ExpirationTime, | ||
): PriorityLevel { | ||
// First check for magic values | ||
if (expirationTime === Done) { | ||
return NoWork; | ||
} | ||
if (expirationTime === Never) { | ||
return OffscreenPriority; | ||
} | ||
const ms = expirationTimeToMs(expirationTime); | ||
if (ms < 0) { | ||
return SynchronousPriority; | ||
} | ||
if (ms === 0) { | ||
return TaskPriority; | ||
} | ||
// Keep this value in sync with priorityToExpirationTime. | ||
if (ms < 120) { | ||
return HighPriority; | ||
} | ||
return LowPriority; | ||
} | ||
exports.expirationTimeToPriorityLevel = expirationTimeToPriorityLevel; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.