Skip to content

Commit dd7229a

Browse files
committed
Use a magic value for task expiration time
There are a few cases related to sync mode where we need to distinguish between work that is scheduled as task and work that is treated like task because it expires. For example, batchedUpdates. We don't want to perform any work until the end of the batch, regardless of how much time has elapsed.
1 parent 2a19015 commit dd7229a

File tree

3 files changed

+55
-50
lines changed

3 files changed

+55
-50
lines changed

src/renderers/dom/fiber/ReactDOMFiberEntry.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -447,11 +447,7 @@ var DOMRenderer = ReactFiberReconciler({
447447
}
448448
},
449449

450-
now() {
451-
// TODO: Use performance.now to enable expiration
452-
// return 0;
453-
return now();
454-
},
450+
now,
455451

456452
canHydrateInstance(
457453
instance: Instance | TextInstance,

src/renderers/shared/fiber/ReactFiberExpirationTime.js

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,13 @@ const invariant = require('fbjs/lib/invariant');
2828
export type ExpirationTime = number;
2929

3030
const Done = 0;
31-
exports.Done = Done;
31+
const Sync = 1;
32+
const Task = 2;
33+
const Never = Infinity;
3234

33-
const MAGIC_NUMBER_OFFSET = 2;
35+
const MAGIC_NUMBER_OFFSET = 10;
3436

35-
const Never = Infinity;
37+
exports.Done = Done;
3638
exports.Never = Infinity;
3739

3840
// 1 unit of expiration time represents 10ms.
@@ -63,11 +65,9 @@ function priorityToExpirationTime(
6365
case NoWork:
6466
return Done;
6567
case SynchronousPriority:
66-
// Return a number lower than the current time, but higher than Done.
67-
return MAGIC_NUMBER_OFFSET - 1;
68+
return Sync;
6869
case TaskPriority:
69-
// Return the current time, so that this work completes in this batch.
70-
return currentTime;
70+
return Task;
7171
case HighPriority:
7272
// Should complete within ~100ms. 120ms max.
7373
return msToExpirationTime(ceiling(100, 20));
@@ -95,16 +95,19 @@ function expirationTimeToPriorityLevel(
9595
expirationTime: ExpirationTime,
9696
): PriorityLevel {
9797
// First check for magic values
98-
if (expirationTime === Done) {
99-
return NoWork;
100-
}
101-
if (expirationTime === Never) {
102-
return OffscreenPriority;
103-
}
104-
if (expirationTime < currentTime) {
105-
return SynchronousPriority;
98+
switch (expirationTime) {
99+
case Done:
100+
return NoWork;
101+
case Sync:
102+
return SynchronousPriority;
103+
case Task:
104+
return TaskPriority;
105+
case Never:
106+
return OffscreenPriority;
107+
default:
108+
break;
106109
}
107-
if (expirationTime === currentTime) {
110+
if (expirationTime <= currentTime) {
108111
return TaskPriority;
109112
}
110113
// Keep this value in sync with priorityToExpirationTime.

src/renderers/shared/fiber/ReactFiberScheduler.js

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -992,7 +992,7 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
992992

993993
// Read the current time from the host environment.
994994
const currentTime = recalculateCurrentTime();
995-
const minExpirationTime = priorityToExpirationTime(
995+
const minExpirationTime = getExpirationTimeForPriority(
996996
currentTime,
997997
minPriorityLevel,
998998
);
@@ -1447,30 +1447,36 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
14471447
const root: FiberRoot = (node.stateNode: any);
14481448
scheduleRoot(root, expirationTime);
14491449
if (!isPerformingWork) {
1450-
if (expirationTime < mostRecentCurrentTime) {
1451-
// This update is synchronous. Perform it now.
1452-
if (isUnbatchingUpdates) {
1453-
// We're inside unbatchedUpdates, which is inside either
1454-
// batchedUpdates or a lifecycle. We should only flush
1455-
// synchronous work, not task work.
1456-
performWork(SynchronousPriority, null);
1457-
} else {
1458-
// Flush both synchronous and task work.
1459-
performWork(TaskPriority, null);
1460-
}
1461-
} else if (expirationTime === mostRecentCurrentTime) {
1462-
invariant(
1463-
isBatchingUpdates,
1464-
'Task updates can only be scheduled as a nested update or ' +
1465-
'inside batchedUpdates. This error is likely caused by a ' +
1466-
'bug in React. Please file an issue.',
1467-
);
1468-
} else {
1469-
// This update is async. Schedule a callback.
1470-
if (!isCallbackScheduled) {
1471-
scheduleDeferredCallback(performDeferredWork);
1472-
isCallbackScheduled = true;
1473-
}
1450+
const priorityLevel = expirationTimeToPriorityLevel(
1451+
mostRecentCurrentTime,
1452+
expirationTime,
1453+
);
1454+
switch (priorityLevel) {
1455+
case SynchronousPriority:
1456+
if (isUnbatchingUpdates) {
1457+
// We're inside unbatchedUpdates, which is inside either
1458+
// batchedUpdates or a lifecycle. We should only flush
1459+
// synchronous work, not task work.
1460+
performWork(SynchronousPriority, null);
1461+
} else {
1462+
// Flush both synchronous and task work.
1463+
performWork(TaskPriority, null);
1464+
}
1465+
break;
1466+
case TaskPriority:
1467+
invariant(
1468+
isBatchingUpdates,
1469+
'Task updates can only be scheduled as a nested update or ' +
1470+
'inside batchedUpdates. This error is likely caused by a ' +
1471+
'bug in React. Please file an issue.',
1472+
);
1473+
break;
1474+
default:
1475+
// This update is async. Schedule a callback.
1476+
if (!isCallbackScheduled) {
1477+
scheduleDeferredCallback(performDeferredWork);
1478+
isCallbackScheduled = true;
1479+
}
14741480
}
14751481
}
14761482
} else {
@@ -1533,11 +1539,11 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
15331539
}
15341540

15351541
function scheduleErrorRecovery(fiber: Fiber) {
1536-
scheduleUpdateImpl(
1537-
fiber,
1538-
priorityToExpirationTime(mostRecentCurrentTime, TaskPriority),
1539-
true,
1542+
const taskTime = getExpirationTimeForPriority(
1543+
mostRecentCurrentTime,
1544+
TaskPriority,
15401545
);
1546+
scheduleUpdateImpl(fiber, taskTime, true);
15411547
}
15421548

15431549
function recalculateCurrentTime(): ExpirationTime {

0 commit comments

Comments
 (0)