@samitouri / QOS-React / commits / 9d756d903f

Revert #14756 changes to ReactFiberScheduler (#14992)

* Revert #14756 changes to ReactFiberScheduler This PR introduced some bugs in concurrent mode during internal testing. Until we figure out a proper solution, I'm going to try reverting it. Not totally certain this is sufficient to unbreak the bugs we found, but I'm using this branch to determine that. * Add back commented out Scheduler import With a note not to use named imports next time we import Scheduler in this module.

Andrew Clark committed Mar 1, 2019 at 13:10 UTC 9d756d903fdd07895fc320962c3fab95fa099bd5
1 file changed +81 -72
packages/react-reconciler/src/ReactFiberScheduler.js
+81 -72
@@ -12,12 +12,16 @@ import type {Batch, FiberRoot} from './ReactFiberRoot';
12 import type {ExpirationTime} from './ReactFiberExpirationTime';
13 import type {Interaction} from 'scheduler/src/Tracing';
14
15 +// Intentionally not named imports because Rollup would use dynamic dispatch for
16 +// CommonJS interop named imports.
17 +// TODO: We're not using this import anymore, but I've left this here so we
18 +// don't accidentally use named imports when we add it back.
19 +// import * as Scheduler from 'scheduler';
20 import {
21 __interactionsRef,
22 __subscriberRef,
23 unstable_wrap as Scheduler_tracing_wrap,
24 } from 'scheduler/tracing';
20 -import * as Scheduler from 'scheduler';
25 import {
26 invokeGuardedCallback,
27 hasCaughtError,
@@ -126,7 +130,7 @@ import {
130 computeAsyncExpiration,
131 computeInteractiveExpiration,
132 } from './ReactFiberExpirationTime';
129 -import {ConcurrentMode, ProfileMode, NoContext} from './ReactTypeOfMode';
133 +import {ConcurrentMode, ProfileMode} from './ReactTypeOfMode';
134 import {enqueueUpdate, resetCurrentlyProcessingQueue} from './ReactUpdateQueue';
135 import {createCapturedValue} from './ReactCapturedValue';
136 import {
@@ -172,19 +176,6 @@ export type Thenable = {
176 then(resolve: () => mixed, reject?: () => mixed): mixed,
177 };
178
175 -// Intentionally not named imports because Rollup would
176 -// use dynamic dispatch for CommonJS interop named imports.
177 -const {
178 - unstable_next: Scheduler_next,
179 - unstable_getCurrentPriorityLevel: getCurrentPriorityLevel,
180 - unstable_runWithPriority: runWithPriority,
181 - unstable_ImmediatePriority: ImmediatePriority,
182 - unstable_UserBlockingPriority: UserBlockingPriority,
183 - unstable_NormalPriority: NormalPriority,
184 - unstable_LowPriority: LowPriority,
185 - unstable_IdlePriority: IdlePriority,
186 -} = Scheduler;
187 -
179 const {ReactCurrentDispatcher, ReactCurrentOwner} = ReactSharedInternals;
180
181 let didWarnAboutStateTransition;
@@ -259,6 +250,11 @@ if (__DEV__) {
250 // Used to ensure computeUniqueAsyncExpiration is monotonically decreasing.
251 let lastUniqueAsyncExpiration: number = Sync - 1;
252
253 +// Represents the expiration time that incoming updates should use. (If this
254 +// is NoWork, use the default strategy: async updates in async mode, sync
255 +// updates in sync mode.)
256 +let expirationContext: ExpirationTime = NoWork;
257 +
258 let isWorking: boolean = false;
259
260 // The next work in progress fiber that we're currently working on.
@@ -811,9 +807,7 @@ function commitRoot(root: FiberRoot, finishedWork: Fiber): void {
807 // here because that code is still in flux.
808 callback = Scheduler_tracing_wrap(callback);
809 }
814 - passiveEffectCallbackHandle = runWithPriority(NormalPriority, () => {
815 - return schedulePassiveEffects(callback);
816 - });
810 + passiveEffectCallbackHandle = schedulePassiveEffects(callback);
811 passiveEffectCallback = callback;
812 }
813
@@ -1597,58 +1591,52 @@ function computeUniqueAsyncExpiration(): ExpirationTime {
1591 }
1592
1593 function computeExpirationForFiber(currentTime: ExpirationTime, fiber: Fiber) {
1600 - const priorityLevel = getCurrentPriorityLevel();
1601 -
1594 let expirationTime;
1603 - if ((fiber.mode & ConcurrentMode) === NoContext) {
1604 - // Outside of concurrent mode, updates are always synchronous.
1605 - expirationTime = Sync;
1606 - } else if (isWorking && !isCommitting) {
1607 - // During render phase, updates expire during as the current render.
1608 - expirationTime = nextRenderExpirationTime;
1595 + if (expirationContext !== NoWork) {
1596 + // An explicit expiration context was set;
1597 + expirationTime = expirationContext;
1598 + } else if (isWorking) {
1599 + if (isCommitting) {
1600 + // Updates that occur during the commit phase should have sync priority
1601 + // by default.
1602 + expirationTime = Sync;
1603 + } else {
1604 + // Updates during the render phase should expire at the same time as
1605 + // the work that is being rendered.
1606 + expirationTime = nextRenderExpirationTime;
1607 + }
1608 } else {
1610 - switch (priorityLevel) {
1611 - case ImmediatePriority:
1612 - expirationTime = Sync;
1613 - break;
1614 - case UserBlockingPriority:
1609 + // No explicit expiration context was set, and we're not currently
1610 + // performing work. Calculate a new expiration time.
1611 + if (fiber.mode & ConcurrentMode) {
1612 + if (isBatchingInteractiveUpdates) {
1613 + // This is an interactive update
1614 expirationTime = computeInteractiveExpiration(currentTime);
1616 - break;
1617 - case NormalPriority:
1618 - // This is a normal, concurrent update
1615 + } else {
1616 + // This is an async update
1617 expirationTime = computeAsyncExpiration(currentTime);
1620 - break;
1621 - case LowPriority:
1622 - case IdlePriority:
1623 - expirationTime = Never;
1624 - break;
1625 - default:
1626 - invariant(
1627 - false,
1628 - 'Unknown priority level. This error is likely caused by a bug in ' +
1629 - 'React. Please file an issue.',
1630 - );
1631 - }
1632 -
1633 - // If we're in the middle of rendering a tree, do not update at the same
1634 - // expiration time that is already rendering.
1635 - if (nextRoot !== null && expirationTime === nextRenderExpirationTime) {
1636 - expirationTime -= 1;
1618 + }
1619 + // If we're in the middle of rendering a tree, do not update at the same
1620 + // expiration time that is already rendering.
1621 + if (nextRoot !== null && expirationTime === nextRenderExpirationTime) {
1622 + expirationTime -= 1;
1623 + }
1624 + } else {
1625 + // This is a sync update
1626 + expirationTime = Sync;
1627 }
1628 }
1639 -
1640 - // Keep track of the lowest pending interactive expiration time. This
1641 - // allows us to synchronously flush all interactive updates
1642 - // when needed.
1643 - // TODO: Move this to renderer?
1644 - if (
1645 - priorityLevel === UserBlockingPriority &&
1646 - (lowestPriorityPendingInteractiveExpirationTime === NoWork ||
1647 - expirationTime < lowestPriorityPendingInteractiveExpirationTime)
1648 - ) {
1649 - lowestPriorityPendingInteractiveExpirationTime = expirationTime;
1629 + if (isBatchingInteractiveUpdates) {
1630 + // This is an interactive update. Keep track of the lowest pending
1631 + // interactive expiration time. This allows us to synchronously flush
1632 + // all interactive updates when needed.
1633 + if (
1634 + lowestPriorityPendingInteractiveExpirationTime === NoWork ||
1635 + expirationTime < lowestPriorityPendingInteractiveExpirationTime
1636 + ) {
1637 + lowestPriorityPendingInteractiveExpirationTime = expirationTime;
1638 + }
1639 }
1651 -
1640 return expirationTime;
1641 }
1642
@@ -1909,6 +1897,20 @@ function scheduleWork(fiber: Fiber, expirationTime: ExpirationTime) {
1897 }
1898 }
1899
1900 +function deferredUpdates<A>(fn: () => A): A {
1901 + const currentTime = requestCurrentTime();
1902 + const previousExpirationContext = expirationContext;
1903 + const previousIsBatchingInteractiveUpdates = isBatchingInteractiveUpdates;
1904 + expirationContext = computeAsyncExpiration(currentTime);
1905 + isBatchingInteractiveUpdates = false;
1906 + try {
1907 + return fn();
1908 + } finally {
1909 + expirationContext = previousExpirationContext;
1910 + isBatchingInteractiveUpdates = previousIsBatchingInteractiveUpdates;
1911 + }
1912 +}
1913 +
1914 function syncUpdates<A, B, C0, D, R>(
1915 fn: (A, B, C0, D) => R,
1916 a: A,
@@ -1916,9 +1918,13 @@ function syncUpdates<A, B, C0, D, R>(
1918 c: C0,
1919 d: D,
1920 ): R {
1919 - return runWithPriority(ImmediatePriority, () => {
1921 + const previousExpirationContext = expirationContext;
1922 + expirationContext = Sync;
1923 + try {
1924 return fn(a, b, c, d);
1921 - });
1925 + } finally {
1926 + expirationContext = previousExpirationContext;
1927 + }
1928 }
1929
1930 // TODO: Everything below this is written as if it has been lifted to the
@@ -1939,6 +1945,7 @@ let unhandledError: mixed | null = null;
1945
1946 let isBatchingUpdates: boolean = false;
1947 let isUnbatchingUpdates: boolean = false;
1948 +let isBatchingInteractiveUpdates: boolean = false;
1949
1950 let completedBatches: Array<Batch> | null = null;
1951
@@ -2450,9 +2457,7 @@ function completeRoot(
2457 lastCommittedRootDuringThisBatch = root;
2458 nestedUpdateCount = 0;
2459 }
2453 - runWithPriority(ImmediatePriority, () => {
2454 - commitRoot(root, finishedWork);
2455 - });
2460 + commitRoot(root, finishedWork);
2461 }
2462
2463 function onUncaughtError(error: mixed) {
@@ -2518,6 +2523,9 @@ function flushSync<A, R>(fn: (a: A) => R, a: A): R {
2523 }
2524
2525 function interactiveUpdates<A, B, R>(fn: (A, B) => R, a: A, b: B): R {
2526 + if (isBatchingInteractiveUpdates) {
2527 + return fn(a, b);
2528 + }
2529 // If there are any pending interactive updates, synchronously flush them.
2530 // This needs to happen before we read any handlers, because the effect of
2531 // the previous event may influence which handlers are called during
@@ -2531,13 +2539,14 @@ function interactiveUpdates<A, B, R>(fn: (A, B) => R, a: A, b: B): R {
2539 performWork(lowestPriorityPendingInteractiveExpirationTime, false);
2540 lowestPriorityPendingInteractiveExpirationTime = NoWork;
2541 }
2542 + const previousIsBatchingInteractiveUpdates = isBatchingInteractiveUpdates;
2543 const previousIsBatchingUpdates = isBatchingUpdates;
2544 + isBatchingInteractiveUpdates = true;
2545 isBatchingUpdates = true;
2546 try {
2537 - return runWithPriority(UserBlockingPriority, () => {
2538 - return fn(a, b);
2539 - });
2547 + return fn(a, b);
2548 } finally {
2549 + isBatchingInteractiveUpdates = previousIsBatchingInteractiveUpdates;
2550 isBatchingUpdates = previousIsBatchingUpdates;
2551 if (!isBatchingUpdates && !isRendering) {
2552 performSyncWork();
@@ -2588,7 +2597,7 @@ export {
2597 unbatchedUpdates,
2598 flushSync,
2599 flushControlled,
2591 - Scheduler_next as deferredUpdates,
2600 + deferredUpdates,
2601 syncUpdates,
2602 interactiveUpdates,
2603 flushInteractiveUpdates,