@samitouri / QOS-React / commits / 169f935f78

Flip expiration times (#13912)

See https://github.com/facebook/react/pull/13912 commit messages for how this was done.

Sophie Alpert committed Oct 30, 2018 at 15:26 UTC 169f935f781c764a8c04f441c5e27b00a0329e8c
9 files changed +79 -160
packages/react-dom/src/client/ReactDOM.js
+1 -1
@@ -400,7 +400,7 @@ ReactRoot.prototype.createBatch = function(): Batch {
400 let insertBefore = firstBatch;
401 while (
402 insertBefore !== null &&
403 - insertBefore._expirationTime <= expirationTime
403 + insertBefore._expirationTime >= expirationTime
404 ) {
405 insertAfter = insertBefore;
406 insertBefore = insertBefore._next;
packages/react-noop-renderer/src/createReactNoop.js
+3 -2
@@ -956,9 +956,10 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
956 rootID: string = DEFAULT_ROOT_ID,
957 ) {
958 const root: any = roots.get(rootID);
959 + const expiration = NoopRenderer.computeUniqueAsyncExpiration();
960 const batch = {
961 _defer: true,
961 - _expirationTime: 1,
962 + _expirationTime: expiration,
963 _onComplete: () => {
964 root.firstBatch = null;
965 },
@@ -969,7 +970,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
970 expect(actual).toEqual(expectedFlush);
971 return (expectedCommit: Array<mixed>) => {
972 batch._defer = false;
972 - NoopRenderer.flushRoot(root, 1);
973 + NoopRenderer.flushRoot(root, expiration);
974 expect(yieldedValues).toEqual(expectedCommit);
975 };
976 },
packages/react-reconciler/src/ReactFiberBeginWork.js
+5 -16
@@ -265,10 +265,7 @@ function updateMemoComponent(
265 return child;
266 }
267 let currentChild = ((current.child: any): Fiber); // This is always exactly one child
268 - if (
269 - updateExpirationTime === NoWork ||
270 - updateExpirationTime > renderExpirationTime
271 - ) {
268 + if (updateExpirationTime < renderExpirationTime) {
269 // This will be the props with resolved defaultProps,
270 // unlike current.memoizedProps which will be the unresolved ones.
271 const prevProps = currentChild.memoizedProps;
@@ -302,11 +299,7 @@ function updateSimpleMemoComponent(
299 updateExpirationTime,
300 renderExpirationTime: ExpirationTime,
301 ): null | Fiber {
305 - if (
306 - current !== null &&
307 - (updateExpirationTime === NoWork ||
308 - updateExpirationTime > renderExpirationTime)
309 - ) {
302 + if (current !== null && updateExpirationTime < renderExpirationTime) {
303 const prevProps = current.memoizedProps;
304 if (
305 shallowEqual(prevProps, nextProps) &&
@@ -1471,10 +1464,7 @@ function bailoutOnAlreadyFinishedWork(
1464
1465 // Check if the children have any pending work.
1466 const childExpirationTime = workInProgress.childExpirationTime;
1474 - if (
1475 - childExpirationTime === NoWork ||
1476 - childExpirationTime > renderExpirationTime
1477 - ) {
1467 + if (childExpirationTime < renderExpirationTime) {
1468 // The children don't have any work either. We can skip them.
1469 // TODO: Once we add back resuming, we should check if the children are
1470 // a work-in-progress set. If so, we need to transfer their effects.
@@ -1500,8 +1490,7 @@ function beginWork(
1490 if (
1491 oldProps === newProps &&
1492 !hasLegacyContextChanged() &&
1503 - (updateExpirationTime === NoWork ||
1504 - updateExpirationTime > renderExpirationTime)
1493 + updateExpirationTime < renderExpirationTime
1494 ) {
1495 // This fiber does not have any pending work. Bailout without entering
1496 // the begin phase. There's still some bookkeeping we that needs to be done
@@ -1550,7 +1539,7 @@ function beginWork(
1539 primaryChildFragment.childExpirationTime;
1540 if (
1541 primaryChildExpirationTime !== NoWork &&
1553 - primaryChildExpirationTime <= renderExpirationTime
1542 + primaryChildExpirationTime >= renderExpirationTime
1543 ) {
1544 // The primary children have pending work. Use the normal path
1545 // to attempt to render the primary children again.
packages/react-reconciler/src/ReactFiberExpirationTime.js
+7 -7
@@ -12,20 +12,20 @@ import MAX_SIGNED_31_BIT_INT from './maxSigned31BitInt';
12 export type ExpirationTime = number;
13
14 export const NoWork = 0;
15 -export const Sync = 1;
16 -export const Never = MAX_SIGNED_31_BIT_INT;
15 +export const Never = 1;
16 +export const Sync = MAX_SIGNED_31_BIT_INT;
17
18 const UNIT_SIZE = 10;
19 -const MAGIC_NUMBER_OFFSET = 2;
19 +const MAGIC_NUMBER_OFFSET = MAX_SIGNED_31_BIT_INT - 1;
20
21 // 1 unit of expiration time represents 10ms.
22 export function msToExpirationTime(ms: number): ExpirationTime {
23 // Always add an offset so that we don't clash with the magic number for NoWork.
24 - return ((ms / UNIT_SIZE) | 0) + MAGIC_NUMBER_OFFSET;
24 + return MAGIC_NUMBER_OFFSET - ((ms / UNIT_SIZE) | 0);
25 }
26
27 export function expirationTimeToMs(expirationTime: ExpirationTime): number {
28 - return (expirationTime - MAGIC_NUMBER_OFFSET) * UNIT_SIZE;
28 + return (MAGIC_NUMBER_OFFSET - expirationTime) * UNIT_SIZE;
29 }
30
31 function ceiling(num: number, precision: number): number {
@@ -38,9 +38,9 @@ function computeExpirationBucket(
38 bucketSizeMs,
39 ): ExpirationTime {
40 return (
41 - MAGIC_NUMBER_OFFSET +
41 + MAGIC_NUMBER_OFFSET -
42 ceiling(
43 - currentTime - MAGIC_NUMBER_OFFSET + expirationInMs / UNIT_SIZE,
43 + MAGIC_NUMBER_OFFSET - currentTime + expirationInMs / UNIT_SIZE,
44 bucketSizeMs / UNIT_SIZE,
45 )
46 );
packages/react-reconciler/src/ReactFiberHooks.js
+2 -5
@@ -404,7 +404,7 @@ export function useReducer<S, A>(
404 let didSkip = false;
405 do {
406 const updateExpirationTime = update.expirationTime;
407 - if (updateExpirationTime > renderExpirationTime) {
407 + if (updateExpirationTime < renderExpirationTime) {
408 // Priority is insufficient. Skip this update. If this is the first
409 // skipped update, the previous update/state is the new base
410 // update/state.
@@ -414,10 +414,7 @@ export function useReducer<S, A>(
414 newBaseState = newState;
415 }
416 // Update the remaining priority in the queue.
417 - if (
418 - remainingExpirationTime === NoWork ||
419 - updateExpirationTime < remainingExpirationTime
420 - ) {
417 + if (updateExpirationTime > remainingExpirationTime) {
418 remainingExpirationTime = updateExpirationTime;
419 }
420 } else {
packages/react-reconciler/src/ReactFiberNewContext.js
+5 -15
@@ -22,7 +22,6 @@ import warningWithoutStack from 'shared/warningWithoutStack';
22 import {isPrimaryRenderer} from './ReactFiberHostConfig';
23 import {createCursor, push, pop} from './ReactFiberStack';
24 import MAX_SIGNED_31_BIT_INT from './maxSigned31BitInt';
25 -import {NoWork} from './ReactFiberExpirationTime';
25 import {ContextProvider, ClassComponent} from 'shared/ReactWorkTags';
26
27 import invariant from 'shared/invariant';
@@ -169,17 +168,13 @@ export function propagateContextChange(
168 enqueueUpdate(fiber, update);
169 }
170
172 - if (
173 - fiber.expirationTime === NoWork ||
174 - fiber.expirationTime > renderExpirationTime
175 - ) {
171 + if (fiber.expirationTime < renderExpirationTime) {
172 fiber.expirationTime = renderExpirationTime;
173 }
174 let alternate = fiber.alternate;
175 if (
176 alternate !== null &&
181 - (alternate.expirationTime === NoWork ||
182 - alternate.expirationTime > renderExpirationTime)
177 + alternate.expirationTime < renderExpirationTime
178 ) {
179 alternate.expirationTime = renderExpirationTime;
180 }
@@ -188,22 +183,17 @@ export function propagateContextChange(
183 let node = fiber.return;
184 while (node !== null) {
185 alternate = node.alternate;
191 - if (
192 - node.childExpirationTime === NoWork ||
193 - node.childExpirationTime > renderExpirationTime
194 - ) {
186 + if (node.childExpirationTime < renderExpirationTime) {
187 node.childExpirationTime = renderExpirationTime;
188 if (
189 alternate !== null &&
198 - (alternate.childExpirationTime === NoWork ||
199 - alternate.childExpirationTime > renderExpirationTime)
190 + alternate.childExpirationTime < renderExpirationTime
191 ) {
192 alternate.childExpirationTime = renderExpirationTime;
193 }
194 } else if (
195 alternate !== null &&
205 - (alternate.childExpirationTime === NoWork ||
206 - alternate.childExpirationTime > renderExpirationTime)
196 + alternate.childExpirationTime < renderExpirationTime
197 ) {
198 alternate.childExpirationTime = renderExpirationTime;
199 } else {
packages/react-reconciler/src/ReactFiberPendingPriority.js
+20 -32
@@ -31,12 +31,12 @@ export function markPendingPriorityLevel(
31 // No other pending updates.
32 root.earliestPendingTime = root.latestPendingTime = expirationTime;
33 } else {
34 - if (earliestPendingTime > expirationTime) {
34 + if (earliestPendingTime < expirationTime) {
35 // This is the earliest pending update.
36 root.earliestPendingTime = expirationTime;
37 } else {
38 const latestPendingTime = root.latestPendingTime;
39 - if (latestPendingTime < expirationTime) {
39 + if (latestPendingTime > expirationTime) {
40 // This is the latest pending update
41 root.latestPendingTime = expirationTime;
42 }
@@ -65,12 +65,12 @@ export function markCommittedPriorityLevels(
65 // Let's see if the previous latest known pending level was just flushed.
66 const latestPendingTime = root.latestPendingTime;
67 if (latestPendingTime !== NoWork) {
68 - if (latestPendingTime < earliestRemainingTime) {
68 + if (latestPendingTime > earliestRemainingTime) {
69 // We've flushed all the known pending levels.
70 root.earliestPendingTime = root.latestPendingTime = NoWork;
71 } else {
72 const earliestPendingTime = root.earliestPendingTime;
73 - if (earliestPendingTime < earliestRemainingTime) {
73 + if (earliestPendingTime > earliestRemainingTime) {
74 // We've flushed the earliest known pending level. Set this to the
75 // latest pending time.
76 root.earliestPendingTime = root.latestPendingTime;
@@ -92,7 +92,7 @@ export function markCommittedPriorityLevels(
92 }
93
94 const latestSuspendedTime = root.latestSuspendedTime;
95 - if (earliestRemainingTime > latestSuspendedTime) {
95 + if (earliestRemainingTime < latestSuspendedTime) {
96 // The earliest remaining level is later than all the suspended work. That
97 // means we've flushed all the suspended work.
98 root.earliestSuspendedTime = NoWork;
@@ -106,7 +106,7 @@ export function markCommittedPriorityLevels(
106 return;
107 }
108
109 - if (earliestRemainingTime < earliestSuspendedTime) {
109 + if (earliestRemainingTime > earliestSuspendedTime) {
110 // The earliest remaining time is earlier than all the suspended work.
111 // Treat it as a pending update.
112 markPendingPriorityLevel(root, earliestRemainingTime);
@@ -128,10 +128,10 @@ export function hasLowerPriorityWork(
128 const latestPingedTime = root.latestPingedTime;
129 return (
130 (latestPendingTime !== NoWork &&
131 - latestPendingTime > erroredExpirationTime) ||
131 + latestPendingTime < erroredExpirationTime) ||
132 (latestSuspendedTime !== NoWork &&
133 - latestSuspendedTime > erroredExpirationTime) ||
134 - (latestPingedTime !== NoWork && latestPingedTime > erroredExpirationTime)
133 + latestSuspendedTime < erroredExpirationTime) ||
134 + (latestPingedTime !== NoWork && latestPingedTime < erroredExpirationTime)
135 );
136 }
137
@@ -143,8 +143,8 @@ export function isPriorityLevelSuspended(
143 const latestSuspendedTime = root.latestSuspendedTime;
144 return (
145 earliestSuspendedTime !== NoWork &&
146 - expirationTime >= earliestSuspendedTime &&
147 - expirationTime <= latestSuspendedTime
146 + expirationTime <= earliestSuspendedTime &&
147 + expirationTime >= latestSuspendedTime
148 );
149 }
150
@@ -180,10 +180,10 @@ export function markSuspendedPriorityLevel(
180 // No other suspended levels.
181 root.earliestSuspendedTime = root.latestSuspendedTime = suspendedTime;
182 } else {
183 - if (earliestSuspendedTime > suspendedTime) {
183 + if (earliestSuspendedTime < suspendedTime) {
184 // This is the earliest suspended level.
185 root.earliestSuspendedTime = suspendedTime;
186 - } else if (latestSuspendedTime < suspendedTime) {
186 + } else if (latestSuspendedTime > suspendedTime) {
187 // This is the latest suspended level
188 root.latestSuspendedTime = suspendedTime;
189 }
@@ -202,7 +202,7 @@ export function markPingedPriorityLevel(
202 // is thrown out and not reused during the restarted render. One way to
203 // invalidate the progressed work is to restart at expirationTime + 1.
204 const latestPingedTime = root.latestPingedTime;
205 - if (latestPingedTime === NoWork || latestPingedTime < pingedTime) {
205 + if (latestPingedTime === NoWork || latestPingedTime > pingedTime) {
206 root.latestPingedTime = pingedTime;
207 }
208 findNextExpirationTimeToWorkOn(pingedTime, root);
@@ -212,7 +212,7 @@ function clearPing(root, completedTime) {
212 // TODO: Track whether the root was pinged during the render phase. If so,
213 // we need to make sure we don't lose track of it.
214 const latestPingedTime = root.latestPingedTime;
215 - if (latestPingedTime !== NoWork && latestPingedTime <= completedTime) {
215 + if (latestPingedTime !== NoWork && latestPingedTime >= completedTime) {
216 root.latestPingedTime = NoWork;
217 }
218 }
@@ -225,18 +225,10 @@ export function findEarliestOutstandingPriorityLevel(
225
226 const earliestPendingTime = root.earliestPendingTime;
227 const earliestSuspendedTime = root.earliestSuspendedTime;
228 - if (
229 - earliestExpirationTime === NoWork ||
230 - (earliestPendingTime !== NoWork &&
231 - earliestPendingTime < earliestExpirationTime)
232 - ) {
228 + if (earliestPendingTime > earliestExpirationTime) {
229 earliestExpirationTime = earliestPendingTime;
230 }
235 - if (
236 - earliestExpirationTime === NoWork ||
237 - (earliestSuspendedTime !== NoWork &&
238 - earliestSuspendedTime < earliestExpirationTime)
239 - ) {
231 + if (earliestSuspendedTime > earliestExpirationTime) {
232 earliestExpirationTime = earliestSuspendedTime;
233 }
234 return earliestExpirationTime;
@@ -247,7 +239,7 @@ export function didExpireAtExpirationTime(
239 currentTime: ExpirationTime,
240 ): void {
241 const expirationTime = root.expirationTime;
250 - if (expirationTime !== NoWork && currentTime >= expirationTime) {
242 + if (expirationTime !== NoWork && currentTime <= expirationTime) {
243 // The root has expired. Flush all work up to the current time.
244 root.nextExpirationTimeToWorkOn = currentTime;
245 }
@@ -269,7 +261,7 @@ function findNextExpirationTimeToWorkOn(completedExpirationTime, root) {
261 if (
262 nextExpirationTimeToWorkOn === NoWork &&
263 (completedExpirationTime === NoWork ||
272 - latestSuspendedTime > completedExpirationTime)
264 + latestSuspendedTime < completedExpirationTime)
265 ) {
266 // The lowest priority suspended work is the work most likely to be
267 // committed next. Let's start rendering it again, so that if it times out,
@@ -278,11 +270,7 @@ function findNextExpirationTimeToWorkOn(completedExpirationTime, root) {
270 }
271
272 let expirationTime = nextExpirationTimeToWorkOn;
281 - if (
282 - expirationTime !== NoWork &&
283 - earliestSuspendedTime !== NoWork &&
284 - earliestSuspendedTime < expirationTime
285 - ) {
273 + if (expirationTime !== NoWork && earliestSuspendedTime > expirationTime) {
274 // Expire using the earliest known expiration time.
275 expirationTime = earliestSuspendedTime;
276 }
packages/react-reconciler/src/ReactFiberScheduler.js
+32 -72
@@ -241,8 +241,8 @@ if (__DEV__) {
241 };
242 }
243
244 -// Used to ensure computeUniqueAsyncExpiration is monotonically increasing.
245 -let lastUniqueAsyncExpiration: number = 0;
244 +// Used to ensure computeUniqueAsyncExpiration is monotonically decreasing.
245 +let lastUniqueAsyncExpiration: number = Sync - 1;
246
247 // Represents the expiration time that incoming updates should use. (If this
248 // is NoWork, use the default strategy: async updates in async mode, sync
@@ -605,9 +605,7 @@ function commitRoot(root: FiberRoot, finishedWork: Fiber): void {
605 const updateExpirationTimeBeforeCommit = finishedWork.expirationTime;
606 const childExpirationTimeBeforeCommit = finishedWork.childExpirationTime;
607 const earliestRemainingTimeBeforeCommit =
608 - updateExpirationTimeBeforeCommit === NoWork ||
609 - (childExpirationTimeBeforeCommit !== NoWork &&
610 - childExpirationTimeBeforeCommit < updateExpirationTimeBeforeCommit)
608 + childExpirationTimeBeforeCommit > updateExpirationTimeBeforeCommit
609 ? childExpirationTimeBeforeCommit
610 : updateExpirationTimeBeforeCommit;
611 markCommittedPriorityLevels(root, earliestRemainingTimeBeforeCommit);
@@ -798,9 +796,7 @@ function commitRoot(root: FiberRoot, finishedWork: Fiber): void {
796 const updateExpirationTimeAfterCommit = finishedWork.expirationTime;
797 const childExpirationTimeAfterCommit = finishedWork.childExpirationTime;
798 const earliestRemainingTimeAfterCommit =
801 - updateExpirationTimeAfterCommit === NoWork ||
802 - (childExpirationTimeAfterCommit !== NoWork &&
803 - childExpirationTimeAfterCommit < updateExpirationTimeAfterCommit)
799 + childExpirationTimeAfterCommit > updateExpirationTimeAfterCommit
800 ? childExpirationTimeAfterCommit
801 : updateExpirationTimeAfterCommit;
802 if (earliestRemainingTimeAfterCommit === NoWork) {
@@ -841,10 +837,7 @@ function commitRoot(root: FiberRoot, finishedWork: Fiber): void {
837 // Only decrement the pending interaction count if we're done.
838 // If there's still work at the current priority,
839 // That indicates that we are waiting for suspense data.
844 - if (
845 - earliestRemainingTimeAfterCommit === NoWork ||
846 - scheduledExpirationTime < earliestRemainingTimeAfterCommit
847 - ) {
840 + if (scheduledExpirationTime > earliestRemainingTimeAfterCommit) {
841 pendingInteractionMap.delete(scheduledExpirationTime);
842
843 scheduledInteractions.forEach(interaction => {
@@ -904,18 +897,10 @@ function resetChildExpirationTime(
897 while (child !== null) {
898 const childUpdateExpirationTime = child.expirationTime;
899 const childChildExpirationTime = child.childExpirationTime;
907 - if (
908 - newChildExpirationTime === NoWork ||
909 - (childUpdateExpirationTime !== NoWork &&
910 - childUpdateExpirationTime < newChildExpirationTime)
911 - ) {
900 + if (childUpdateExpirationTime > newChildExpirationTime) {
901 newChildExpirationTime = childUpdateExpirationTime;
902 }
914 - if (
915 - newChildExpirationTime === NoWork ||
916 - (childChildExpirationTime !== NoWork &&
917 - childChildExpirationTime < newChildExpirationTime)
918 - ) {
903 + if (childChildExpirationTime > newChildExpirationTime) {
904 newChildExpirationTime = childChildExpirationTime;
905 }
906 if (shouldBubbleActualDurations) {
@@ -931,18 +916,10 @@ function resetChildExpirationTime(
916 while (child !== null) {
917 const childUpdateExpirationTime = child.expirationTime;
918 const childChildExpirationTime = child.childExpirationTime;
934 - if (
935 - newChildExpirationTime === NoWork ||
936 - (childUpdateExpirationTime !== NoWork &&
937 - childUpdateExpirationTime < newChildExpirationTime)
938 - ) {
919 + if (childUpdateExpirationTime > newChildExpirationTime) {
920 newChildExpirationTime = childUpdateExpirationTime;
921 }
941 - if (
942 - newChildExpirationTime === NoWork ||
943 - (childChildExpirationTime !== NoWork &&
944 - childChildExpirationTime < newChildExpirationTime)
945 - ) {
922 + if (childChildExpirationTime > newChildExpirationTime) {
923 newChildExpirationTime = childChildExpirationTime;
924 }
925 child = child.sibling;
@@ -1244,7 +1221,7 @@ function renderRoot(root: FiberRoot, isYieldy: boolean): void {
1221 const interactions: Set<Interaction> = new Set();
1222 root.pendingInteractionMap.forEach(
1223 (scheduledInteractions, scheduledExpirationTime) => {
1247 - if (scheduledExpirationTime <= expirationTime) {
1224 + if (scheduledExpirationTime >= expirationTime) {
1225 scheduledInteractions.forEach(interaction =>
1226 interactions.add(interaction),
1227 );
@@ -1550,11 +1527,11 @@ function computeThreadID(
1527 function computeUniqueAsyncExpiration(): ExpirationTime {
1528 const currentTime = requestCurrentTime();
1529 let result = computeAsyncExpiration(currentTime);
1553 - if (result <= lastUniqueAsyncExpiration) {
1530 + if (result >= lastUniqueAsyncExpiration) {
1531 // Since we assume the current time monotonically increases, we only hit
1532 // this branch when computeUniqueAsyncExpiration is fired multiple times
1533 // within a 200ms window (or whatever the async bucket size is).
1557 - result = lastUniqueAsyncExpiration + 1;
1534 + result = lastUniqueAsyncExpiration - 1;
1535 }
1536 lastUniqueAsyncExpiration = result;
1537 return lastUniqueAsyncExpiration;
@@ -1589,7 +1566,7 @@ function computeExpirationForFiber(currentTime: ExpirationTime, fiber: Fiber) {
1566 // If we're in the middle of rendering a tree, do not update at the same
1567 // expiration time that is already rendering.
1568 if (nextRoot !== null && expirationTime === nextRenderExpirationTime) {
1592 - expirationTime += 1;
1569 + expirationTime -= 1;
1570 }
1571 } else {
1572 // This is a sync update
@@ -1600,7 +1577,10 @@ function computeExpirationForFiber(currentTime: ExpirationTime, fiber: Fiber) {
1577 // This is an interactive update. Keep track of the lowest pending
1578 // interactive expiration time. This allows us to synchronously flush
1579 // all interactive updates when needed.
1603 - if (expirationTime > lowestPriorityPendingInteractiveExpirationTime) {
1580 + if (
1581 + lowestPriorityPendingInteractiveExpirationTime === NoWork ||
1582 + expirationTime < lowestPriorityPendingInteractiveExpirationTime
1583 + ) {
1584 lowestPriorityPendingInteractiveExpirationTime = expirationTime;
1585 }
1586 }
@@ -1694,18 +1674,11 @@ function scheduleWorkToRoot(fiber: Fiber, expirationTime): FiberRoot | null {
1674 }
1675
1676 // Update the source fiber's expiration time
1697 - if (
1698 - fiber.expirationTime === NoWork ||
1699 - fiber.expirationTime > expirationTime
1700 - ) {
1677 + if (fiber.expirationTime < expirationTime) {
1678 fiber.expirationTime = expirationTime;
1679 }
1680 let alternate = fiber.alternate;
1704 - if (
1705 - alternate !== null &&
1706 - (alternate.expirationTime === NoWork ||
1707 - alternate.expirationTime > expirationTime)
1708 - ) {
1681 + if (alternate !== null && alternate.expirationTime < expirationTime) {
1682 alternate.expirationTime = expirationTime;
1683 }
1684 // Walk the parent path to the root and update the child expiration time.
@@ -1716,22 +1689,17 @@ function scheduleWorkToRoot(fiber: Fiber, expirationTime): FiberRoot | null {
1689 } else {
1690 while (node !== null) {
1691 alternate = node.alternate;
1719 - if (
1720 - node.childExpirationTime === NoWork ||
1721 - node.childExpirationTime > expirationTime
1722 - ) {
1692 + if (node.childExpirationTime < expirationTime) {
1693 node.childExpirationTime = expirationTime;
1694 if (
1695 alternate !== null &&
1726 - (alternate.childExpirationTime === NoWork ||
1727 - alternate.childExpirationTime > expirationTime)
1696 + alternate.childExpirationTime < expirationTime
1697 ) {
1698 alternate.childExpirationTime = expirationTime;
1699 }
1700 } else if (
1701 alternate !== null &&
1733 - (alternate.childExpirationTime === NoWork ||
1734 - alternate.childExpirationTime > expirationTime)
1702 + alternate.childExpirationTime < expirationTime
1703 ) {
1704 alternate.childExpirationTime = expirationTime;
1705 }
@@ -1806,7 +1774,7 @@ function scheduleWork(fiber: Fiber, expirationTime: ExpirationTime) {
1774 if (
1775 !isWorking &&
1776 nextRenderExpirationTime !== NoWork &&
1809 - expirationTime < nextRenderExpirationTime
1777 + expirationTime > nextRenderExpirationTime
1778 ) {
1779 // This is an interruption. (Used for performance tracking.)
1780 interruptedBy = fiber;
@@ -1911,7 +1879,7 @@ function scheduleCallbackWithExpirationTime(
1879 ) {
1880 if (callbackExpirationTime !== NoWork) {
1881 // A callback is already scheduled. Check its expiration time (timeout).
1914 - if (expirationTime > callbackExpirationTime) {
1882 + if (expirationTime < callbackExpirationTime) {
1883 // Existing callback has sufficient timeout. Exit.
1884 return;
1885 } else {
@@ -2083,10 +2051,7 @@ function addRootToSchedule(root: FiberRoot, expirationTime: ExpirationTime) {
2051 } else {
2052 // This root is already scheduled, but its priority may have increased.
2053 const remainingExpirationTime = root.expirationTime;
2086 - if (
2087 - remainingExpirationTime === NoWork ||
2088 - expirationTime < remainingExpirationTime
2089 - ) {
2054 + if (expirationTime > remainingExpirationTime) {
2055 // Update the priority.
2056 root.expirationTime = expirationTime;
2057 }
@@ -2135,10 +2100,7 @@ function findHighestPriorityRoot() {
2100 }
2101 root = previousScheduledRoot.nextScheduledRoot;
2102 } else {
2138 - if (
2139 - highestPriorityWork === NoWork ||
2140 - remainingExpirationTime < highestPriorityWork
2141 - ) {
2103 + if (remainingExpirationTime > highestPriorityWork) {
2104 // Update the priority, if it's higher
2105 highestPriorityWork = remainingExpirationTime;
2106 highestPriorityRoot = root;
@@ -2214,7 +2176,7 @@ function performWork(minExpirationTime: ExpirationTime, isYieldy: boolean) {
2176 currentSchedulerTime = currentRendererTime;
2177
2178 if (enableUserTimingAPI) {
2217 - const didExpire = nextFlushedExpirationTime < currentRendererTime;
2179 + const didExpire = nextFlushedExpirationTime > currentRendererTime;
2180 const timeout = expirationTimeToMs(nextFlushedExpirationTime);
2181 stopRequestCallbackTimer(didExpire, timeout);
2182 }
@@ -2222,14 +2184,13 @@ function performWork(minExpirationTime: ExpirationTime, isYieldy: boolean) {
2184 while (
2185 nextFlushedRoot !== null &&
2186 nextFlushedExpirationTime !== NoWork &&
2225 - (minExpirationTime === NoWork ||
2226 - minExpirationTime >= nextFlushedExpirationTime) &&
2227 - !(didYield && currentRendererTime < nextFlushedExpirationTime)
2187 + minExpirationTime <= nextFlushedExpirationTime &&
2188 + !(didYield && currentRendererTime > nextFlushedExpirationTime)
2189 ) {
2190 performWorkOnRoot(
2191 nextFlushedRoot,
2192 nextFlushedExpirationTime,
2232 - currentRendererTime < nextFlushedExpirationTime,
2193 + currentRendererTime > nextFlushedExpirationTime,
2194 );
2195 findHighestPriorityRoot();
2196 recomputeCurrentRendererTime();
@@ -2239,8 +2200,7 @@ function performWork(minExpirationTime: ExpirationTime, isYieldy: boolean) {
2200 while (
2201 nextFlushedRoot !== null &&
2202 nextFlushedExpirationTime !== NoWork &&
2242 - (minExpirationTime === NoWork ||
2243 - minExpirationTime >= nextFlushedExpirationTime)
2203 + minExpirationTime <= nextFlushedExpirationTime
2204 ) {
2205 performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime, false);
2206 findHighestPriorityRoot();
@@ -2395,7 +2355,7 @@ function completeRoot(
2355 ): void {
2356 // Check if there's a batch that matches this expiration time.
2357 const firstBatch = root.firstBatch;
2398 - if (firstBatch !== null && firstBatch._expirationTime <= expirationTime) {
2358 + if (firstBatch !== null && firstBatch._expirationTime >= expirationTime) {
2359 if (completedBatches === null) {
2360 completedBatches = [firstBatch];
2361 } else {
packages/react-reconciler/src/ReactUpdateQueue.js
+4 -10
@@ -425,7 +425,7 @@ export function processUpdateQueue<State>(
425 let resultState = newBaseState;
426 while (update !== null) {
427 const updateExpirationTime = update.expirationTime;
428 - if (updateExpirationTime > renderExpirationTime) {
428 + if (updateExpirationTime < renderExpirationTime) {
429 // This update does not have sufficient priority. Skip it.
430 if (newFirstUpdate === null) {
431 // This is the first skipped update. It will be the first update in
@@ -437,10 +437,7 @@ export function processUpdateQueue<State>(
437 }
438 // Since this update will remain in the list, update the remaining
439 // expiration time.
440 - if (
441 - newExpirationTime === NoWork ||
442 - newExpirationTime > updateExpirationTime
443 - ) {
440 + if (newExpirationTime < updateExpirationTime) {
441 newExpirationTime = updateExpirationTime;
442 }
443 } else {
@@ -476,7 +473,7 @@ export function processUpdateQueue<State>(
473 update = queue.firstCapturedUpdate;
474 while (update !== null) {
475 const updateExpirationTime = update.expirationTime;
479 - if (updateExpirationTime > renderExpirationTime) {
476 + if (updateExpirationTime < renderExpirationTime) {
477 // This update does not have sufficient priority. Skip it.
478 if (newFirstCapturedUpdate === null) {
479 // This is the first skipped captured update. It will be the first
@@ -490,10 +487,7 @@ export function processUpdateQueue<State>(
487 }
488 // Since this update will remain in the list, update the remaining
489 // expiration time.
493 - if (
494 - newExpirationTime === NoWork ||
495 - newExpirationTime > updateExpirationTime
496 - ) {
490 + if (newExpirationTime < updateExpirationTime) {
491 newExpirationTime = updateExpirationTime;
492 }
493 } else {