Add feature flag for setting update lane priority (#19401)

* Add feature flag for setting update lane priority

* Remove second feature flag

* Refactor feature flag locations

* Add missing else
This commit is contained in:
Ricky
2020-08-06 12:47:32 -04:00
committed by GitHub
parent 5bdd4c8c60
commit 32ff428687
7 changed files with 479 additions and 223 deletions
+23 -7
View File
@@ -38,7 +38,10 @@ import {
import getEventTarget from './getEventTarget';
import {getClosestInstanceFromNode} from '../client/ReactDOMComponentTree';
import {enableLegacyFBSupport} from 'shared/ReactFeatureFlags';
import {
enableLegacyFBSupport,
decoupleUpdatePriorityFromScheduler,
} from 'shared/ReactFeatureFlags';
import {
UserBlockingEvent,
ContinuousEvent,
@@ -147,10 +150,25 @@ function dispatchUserBlockingUpdate(
container,
nativeEvent,
) {
// TODO: Double wrapping is necessary while we decouple Scheduler priority.
const previousPriority = getCurrentUpdateLanePriority();
try {
setCurrentUpdateLanePriority(InputContinuousLanePriority);
if (decoupleUpdatePriorityFromScheduler) {
const previousPriority = getCurrentUpdateLanePriority();
try {
// TODO: Double wrapping is necessary while we decouple Scheduler priority.
setCurrentUpdateLanePriority(InputContinuousLanePriority);
runWithPriority(
UserBlockingPriority,
dispatchEvent.bind(
null,
domEventName,
eventSystemFlags,
container,
nativeEvent,
),
);
} finally {
setCurrentUpdateLanePriority(previousPriority);
}
} else {
runWithPriority(
UserBlockingPriority,
dispatchEvent.bind(
@@ -161,8 +179,6 @@ function dispatchUserBlockingUpdate(
nativeEvent,
),
);
} finally {
setCurrentUpdateLanePriority(previousPriority);
}
}
@@ -26,6 +26,7 @@ import {
enableDebugTracing,
enableSchedulingProfiler,
enableNewReconciler,
decoupleUpdatePriorityFromScheduler,
} from 'shared/ReactFeatureFlags';
import {NoMode, BlockingMode, DebugTracingMode} from './ReactTypeOfMode';
@@ -1506,34 +1507,64 @@ function rerenderDeferredValue<T>(
function startTransition(setPending, config, callback) {
const priorityLevel = getCurrentPriorityLevel();
const previousLanePriority = getCurrentUpdateLanePriority();
setCurrentUpdateLanePriority(
higherLanePriority(previousLanePriority, InputContinuousLanePriority),
);
runWithPriority(
priorityLevel < UserBlockingPriority ? UserBlockingPriority : priorityLevel,
() => {
setPending(true);
},
);
if (decoupleUpdatePriorityFromScheduler) {
const previousLanePriority = getCurrentUpdateLanePriority();
setCurrentUpdateLanePriority(
higherLanePriority(previousLanePriority, InputContinuousLanePriority),
);
// If there's no SuspenseConfig set, we'll use the DefaultLanePriority for this transition.
setCurrentUpdateLanePriority(DefaultLanePriority);
runWithPriority(
priorityLevel < UserBlockingPriority
? UserBlockingPriority
: priorityLevel,
() => {
setPending(true);
},
);
runWithPriority(
priorityLevel > NormalPriority ? NormalPriority : priorityLevel,
() => {
const previousConfig = ReactCurrentBatchConfig.suspense;
ReactCurrentBatchConfig.suspense = config === undefined ? null : config;
try {
setPending(false);
callback();
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
ReactCurrentBatchConfig.suspense = previousConfig;
}
},
);
// If there's no SuspenseConfig set, we'll use the DefaultLanePriority for this transition.
setCurrentUpdateLanePriority(DefaultLanePriority);
runWithPriority(
priorityLevel > NormalPriority ? NormalPriority : priorityLevel,
() => {
const previousConfig = ReactCurrentBatchConfig.suspense;
ReactCurrentBatchConfig.suspense = config === undefined ? null : config;
try {
setPending(false);
callback();
} finally {
if (decoupleUpdatePriorityFromScheduler) {
setCurrentUpdateLanePriority(previousLanePriority);
}
ReactCurrentBatchConfig.suspense = previousConfig;
}
},
);
} else {
runWithPriority(
priorityLevel < UserBlockingPriority
? UserBlockingPriority
: priorityLevel,
() => {
setPending(true);
},
);
runWithPriority(
priorityLevel > NormalPriority ? NormalPriority : priorityLevel,
() => {
const previousConfig = ReactCurrentBatchConfig.suspense;
ReactCurrentBatchConfig.suspense = config === undefined ? null : config;
try {
setPending(false);
callback();
} finally {
ReactCurrentBatchConfig.suspense = previousConfig;
}
},
);
}
}
function mountTransition(
@@ -26,6 +26,7 @@ import {
enableDebugTracing,
enableSchedulingProfiler,
enableNewReconciler,
decoupleUpdatePriorityFromScheduler,
} from 'shared/ReactFeatureFlags';
import {NoMode, BlockingMode, DebugTracingMode} from './ReactTypeOfMode';
@@ -1505,34 +1506,64 @@ function rerenderDeferredValue<T>(
function startTransition(setPending, config, callback) {
const priorityLevel = getCurrentPriorityLevel();
const previousLanePriority = getCurrentUpdateLanePriority();
setCurrentUpdateLanePriority(
higherLanePriority(previousLanePriority, InputContinuousLanePriority),
);
runWithPriority(
priorityLevel < UserBlockingPriority ? UserBlockingPriority : priorityLevel,
() => {
setPending(true);
},
);
if (decoupleUpdatePriorityFromScheduler) {
const previousLanePriority = getCurrentUpdateLanePriority();
setCurrentUpdateLanePriority(
higherLanePriority(previousLanePriority, InputContinuousLanePriority),
);
// If there's no SuspenseConfig set, we'll use the DefaultLanePriority for this transition.
setCurrentUpdateLanePriority(DefaultLanePriority);
runWithPriority(
priorityLevel < UserBlockingPriority
? UserBlockingPriority
: priorityLevel,
() => {
setPending(true);
},
);
runWithPriority(
priorityLevel > NormalPriority ? NormalPriority : priorityLevel,
() => {
const previousConfig = ReactCurrentBatchConfig.suspense;
ReactCurrentBatchConfig.suspense = config === undefined ? null : config;
try {
setPending(false);
callback();
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
ReactCurrentBatchConfig.suspense = previousConfig;
}
},
);
// If there's no SuspenseConfig set, we'll use the DefaultLanePriority for this transition.
setCurrentUpdateLanePriority(DefaultLanePriority);
runWithPriority(
priorityLevel > NormalPriority ? NormalPriority : priorityLevel,
() => {
const previousConfig = ReactCurrentBatchConfig.suspense;
ReactCurrentBatchConfig.suspense = config === undefined ? null : config;
try {
setPending(false);
callback();
} finally {
if (decoupleUpdatePriorityFromScheduler) {
setCurrentUpdateLanePriority(previousLanePriority);
}
ReactCurrentBatchConfig.suspense = previousConfig;
}
},
);
} else {
runWithPriority(
priorityLevel < UserBlockingPriority
? UserBlockingPriority
: priorityLevel,
() => {
setPending(true);
},
);
runWithPriority(
priorityLevel > NormalPriority ? NormalPriority : priorityLevel,
() => {
const previousConfig = ReactCurrentBatchConfig.suspense;
ReactCurrentBatchConfig.suspense = config === undefined ? null : config;
try {
setPending(false);
callback();
} finally {
ReactCurrentBatchConfig.suspense = previousConfig;
}
},
);
}
}
function mountTransition(
@@ -1163,13 +1163,16 @@ export function flushDiscreteUpdates() {
}
export function deferredUpdates<A>(fn: () => A): A {
// TODO: Remove in favor of Scheduler.next
const previousLanePriority = getCurrentUpdateLanePriority();
try {
setCurrentUpdateLanePriority(DefaultLanePriority);
if (decoupleUpdatePriorityFromScheduler) {
const previousLanePriority = getCurrentUpdateLanePriority();
try {
setCurrentUpdateLanePriority(DefaultLanePriority);
return runWithPriority(NormalSchedulerPriority, fn);
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
}
} else {
return runWithPriority(NormalSchedulerPriority, fn);
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
}
}
@@ -1225,20 +1228,35 @@ export function discreteUpdates<A, B, C, D, R>(
): R {
const prevExecutionContext = executionContext;
executionContext |= DiscreteEventContext;
const previousLanePriority = getCurrentUpdateLanePriority();
try {
setCurrentUpdateLanePriority(InputDiscreteLanePriority);
// Should this
return runWithPriority(
UserBlockingSchedulerPriority,
fn.bind(null, a, b, c, d),
);
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
executionContext = prevExecutionContext;
if (executionContext === NoContext) {
// Flush the immediate callbacks that were scheduled during this batch
flushSyncCallbackQueue();
if (decoupleUpdatePriorityFromScheduler) {
const previousLanePriority = getCurrentUpdateLanePriority();
try {
setCurrentUpdateLanePriority(InputDiscreteLanePriority);
return runWithPriority(
UserBlockingSchedulerPriority,
fn.bind(null, a, b, c, d),
);
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
executionContext = prevExecutionContext;
if (executionContext === NoContext) {
// Flush the immediate callbacks that were scheduled during this batch
flushSyncCallbackQueue();
}
}
} else {
try {
return runWithPriority(
UserBlockingSchedulerPriority,
fn.bind(null, a, b, c, d),
);
} finally {
executionContext = prevExecutionContext;
if (executionContext === NoContext) {
// Flush the immediate callbacks that were scheduled during this batch
flushSyncCallbackQueue();
}
}
}
}
@@ -1271,37 +1289,67 @@ export function flushSync<A, R>(fn: A => R, a: A): R {
return fn(a);
}
executionContext |= BatchedContext;
const previousLanePriority = getCurrentUpdateLanePriority();
try {
setCurrentUpdateLanePriority(SyncLanePriority);
if (fn) {
return runWithPriority(ImmediateSchedulerPriority, fn.bind(null, a));
} else {
return (undefined: $FlowFixMe);
if (decoupleUpdatePriorityFromScheduler) {
const previousLanePriority = getCurrentUpdateLanePriority();
try {
setCurrentUpdateLanePriority(SyncLanePriority);
if (fn) {
return runWithPriority(ImmediateSchedulerPriority, fn.bind(null, a));
} else {
return (undefined: $FlowFixMe);
}
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
executionContext = prevExecutionContext;
// Flush the immediate callbacks that were scheduled during this batch.
// Note that this will happen even if batchedUpdates is higher up
// the stack.
flushSyncCallbackQueue();
}
} else {
try {
if (fn) {
return runWithPriority(ImmediateSchedulerPriority, fn.bind(null, a));
} else {
return (undefined: $FlowFixMe);
}
} finally {
executionContext = prevExecutionContext;
// Flush the immediate callbacks that were scheduled during this batch.
// Note that this will happen even if batchedUpdates is higher up
// the stack.
flushSyncCallbackQueue();
}
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
executionContext = prevExecutionContext;
// Flush the immediate callbacks that were scheduled during this batch.
// Note that this will happen even if batchedUpdates is higher up
// the stack.
flushSyncCallbackQueue();
}
}
export function flushControlled(fn: () => mixed): void {
const prevExecutionContext = executionContext;
executionContext |= BatchedContext;
const previousLanePriority = getCurrentUpdateLanePriority();
try {
setCurrentUpdateLanePriority(SyncLanePriority);
runWithPriority(ImmediateSchedulerPriority, fn);
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
executionContext = prevExecutionContext;
if (executionContext === NoContext) {
// Flush the immediate callbacks that were scheduled during this batch
flushSyncCallbackQueue();
if (decoupleUpdatePriorityFromScheduler) {
const previousLanePriority = getCurrentUpdateLanePriority();
try {
setCurrentUpdateLanePriority(SyncLanePriority);
runWithPriority(ImmediateSchedulerPriority, fn);
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
executionContext = prevExecutionContext;
if (executionContext === NoContext) {
// Flush the immediate callbacks that were scheduled during this batch
flushSyncCallbackQueue();
}
}
} else {
try {
runWithPriority(ImmediateSchedulerPriority, fn);
} finally {
executionContext = prevExecutionContext;
if (executionContext === NoContext) {
// Flush the immediate callbacks that were scheduled during this batch
flushSyncCallbackQueue();
}
}
}
}
@@ -2122,8 +2170,11 @@ function commitRootImpl(root, renderPriorityLevel) {
}
if (firstEffect !== null) {
const previousLanePriority = getCurrentUpdateLanePriority();
setCurrentUpdateLanePriority(SyncLanePriority);
let previousLanePriority;
if (decoupleUpdatePriorityFromScheduler) {
previousLanePriority = getCurrentUpdateLanePriority();
setCurrentUpdateLanePriority(SyncLanePriority);
}
const prevExecutionContext = executionContext;
executionContext |= CommitContext;
@@ -2214,8 +2265,10 @@ function commitRootImpl(root, renderPriorityLevel) {
}
executionContext = prevExecutionContext;
// Reset the priority to the previous non-sync value.
setCurrentUpdateLanePriority(previousLanePriority);
if (decoupleUpdatePriorityFromScheduler && previousLanePriority != null) {
// Reset the priority to the previous non-sync value.
setCurrentUpdateLanePriority(previousLanePriority);
}
} else {
// No effects.
root.current = finishedWork;
@@ -2655,14 +2708,18 @@ export function flushPassiveEffects(): boolean {
? NormalSchedulerPriority
: pendingPassiveEffectsRenderPriority;
pendingPassiveEffectsRenderPriority = NoSchedulerPriority;
const previousLanePriority = getCurrentUpdateLanePriority();
try {
setCurrentUpdateLanePriority(
schedulerPriorityToLanePriority(priorityLevel),
);
if (decoupleUpdatePriorityFromScheduler) {
const previousLanePriority = getCurrentUpdateLanePriority();
try {
setCurrentUpdateLanePriority(
schedulerPriorityToLanePriority(priorityLevel),
);
return runWithPriority(priorityLevel, flushPassiveEffectsImpl);
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
}
} else {
return runWithPriority(priorityLevel, flushPassiveEffectsImpl);
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
}
}
return false;
@@ -1147,13 +1147,16 @@ export function flushDiscreteUpdates() {
}
export function deferredUpdates<A>(fn: () => A): A {
// TODO: Remove in favor of Scheduler.next
const previousLanePriority = getCurrentUpdateLanePriority();
try {
setCurrentUpdateLanePriority(DefaultLanePriority);
if (decoupleUpdatePriorityFromScheduler) {
const previousLanePriority = getCurrentUpdateLanePriority();
try {
setCurrentUpdateLanePriority(DefaultLanePriority);
return runWithPriority(NormalSchedulerPriority, fn);
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
}
} else {
return runWithPriority(NormalSchedulerPriority, fn);
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
}
}
@@ -1209,20 +1212,35 @@ export function discreteUpdates<A, B, C, D, R>(
): R {
const prevExecutionContext = executionContext;
executionContext |= DiscreteEventContext;
const previousLanePriority = getCurrentUpdateLanePriority();
try {
setCurrentUpdateLanePriority(InputDiscreteLanePriority);
// Should this
return runWithPriority(
UserBlockingSchedulerPriority,
fn.bind(null, a, b, c, d),
);
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
executionContext = prevExecutionContext;
if (executionContext === NoContext) {
// Flush the immediate callbacks that were scheduled during this batch
flushSyncCallbackQueue();
if (decoupleUpdatePriorityFromScheduler) {
const previousLanePriority = getCurrentUpdateLanePriority();
try {
setCurrentUpdateLanePriority(InputDiscreteLanePriority);
return runWithPriority(
UserBlockingSchedulerPriority,
fn.bind(null, a, b, c, d),
);
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
executionContext = prevExecutionContext;
if (executionContext === NoContext) {
// Flush the immediate callbacks that were scheduled during this batch
flushSyncCallbackQueue();
}
}
} else {
try {
return runWithPriority(
UserBlockingSchedulerPriority,
fn.bind(null, a, b, c, d),
);
} finally {
executionContext = prevExecutionContext;
if (executionContext === NoContext) {
// Flush the immediate callbacks that were scheduled during this batch
flushSyncCallbackQueue();
}
}
}
}
@@ -1255,37 +1273,67 @@ export function flushSync<A, R>(fn: A => R, a: A): R {
return fn(a);
}
executionContext |= BatchedContext;
const previousLanePriority = getCurrentUpdateLanePriority();
try {
setCurrentUpdateLanePriority(SyncLanePriority);
if (fn) {
return runWithPriority(ImmediateSchedulerPriority, fn.bind(null, a));
} else {
return (undefined: $FlowFixMe);
if (decoupleUpdatePriorityFromScheduler) {
const previousLanePriority = getCurrentUpdateLanePriority();
try {
setCurrentUpdateLanePriority(SyncLanePriority);
if (fn) {
return runWithPriority(ImmediateSchedulerPriority, fn.bind(null, a));
} else {
return (undefined: $FlowFixMe);
}
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
executionContext = prevExecutionContext;
// Flush the immediate callbacks that were scheduled during this batch.
// Note that this will happen even if batchedUpdates is higher up
// the stack.
flushSyncCallbackQueue();
}
} else {
try {
if (fn) {
return runWithPriority(ImmediateSchedulerPriority, fn.bind(null, a));
} else {
return (undefined: $FlowFixMe);
}
} finally {
executionContext = prevExecutionContext;
// Flush the immediate callbacks that were scheduled during this batch.
// Note that this will happen even if batchedUpdates is higher up
// the stack.
flushSyncCallbackQueue();
}
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
executionContext = prevExecutionContext;
// Flush the immediate callbacks that were scheduled during this batch.
// Note that this will happen even if batchedUpdates is higher up
// the stack.
flushSyncCallbackQueue();
}
}
export function flushControlled(fn: () => mixed): void {
const prevExecutionContext = executionContext;
executionContext |= BatchedContext;
const previousLanePriority = getCurrentUpdateLanePriority();
try {
setCurrentUpdateLanePriority(SyncLanePriority);
runWithPriority(ImmediateSchedulerPriority, fn);
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
executionContext = prevExecutionContext;
if (executionContext === NoContext) {
// Flush the immediate callbacks that were scheduled during this batch
flushSyncCallbackQueue();
if (decoupleUpdatePriorityFromScheduler) {
const previousLanePriority = getCurrentUpdateLanePriority();
try {
setCurrentUpdateLanePriority(SyncLanePriority);
runWithPriority(ImmediateSchedulerPriority, fn);
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
executionContext = prevExecutionContext;
if (executionContext === NoContext) {
// Flush the immediate callbacks that were scheduled during this batch
flushSyncCallbackQueue();
}
}
} else {
try {
runWithPriority(ImmediateSchedulerPriority, fn);
} finally {
executionContext = prevExecutionContext;
if (executionContext === NoContext) {
// Flush the immediate callbacks that were scheduled during this batch
flushSyncCallbackQueue();
}
}
}
}
@@ -2019,8 +2067,11 @@ function commitRootImpl(root, renderPriorityLevel) {
}
if (firstEffect !== null) {
const previousLanePriority = getCurrentUpdateLanePriority();
setCurrentUpdateLanePriority(SyncLanePriority);
let previousLanePriority;
if (decoupleUpdatePriorityFromScheduler) {
previousLanePriority = getCurrentUpdateLanePriority();
setCurrentUpdateLanePriority(SyncLanePriority);
}
const prevExecutionContext = executionContext;
executionContext |= CommitContext;
@@ -2143,8 +2194,10 @@ function commitRootImpl(root, renderPriorityLevel) {
}
executionContext = prevExecutionContext;
// Reset the priority to the previous non-sync value.
setCurrentUpdateLanePriority(previousLanePriority);
if (decoupleUpdatePriorityFromScheduler && previousLanePriority != null) {
// Reset the priority to the previous non-sync value.
setCurrentUpdateLanePriority(previousLanePriority);
}
} else {
// No effects.
root.current = finishedWork;
@@ -2463,14 +2516,18 @@ export function flushPassiveEffects(): boolean {
? NormalSchedulerPriority
: pendingPassiveEffectsRenderPriority;
pendingPassiveEffectsRenderPriority = NoSchedulerPriority;
const previousLanePriority = getCurrentUpdateLanePriority();
try {
setCurrentUpdateLanePriority(
schedulerPriorityToLanePriority(priorityLevel),
);
if (decoupleUpdatePriorityFromScheduler) {
const previousLanePriority = getCurrentUpdateLanePriority();
try {
setCurrentUpdateLanePriority(
schedulerPriorityToLanePriority(priorityLevel),
);
return runWithPriority(priorityLevel, flushPassiveEffectsImpl);
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
}
} else {
return runWithPriority(priorityLevel, flushPassiveEffectsImpl);
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
}
}
return false;
@@ -13,7 +13,10 @@ import type {ReactPriorityLevel} from './ReactInternalTypes';
// CommonJS interop named imports.
import * as Scheduler from 'scheduler';
import {__interactionsRef} from 'scheduler/tracing';
import {enableSchedulerTracing} from 'shared/ReactFeatureFlags';
import {
enableSchedulerTracing,
decoupleUpdatePriorityFromScheduler,
} from 'shared/ReactFeatureFlags';
import invariant from 'shared/invariant';
import {
SyncLanePriority,
@@ -176,34 +179,63 @@ function flushSyncCallbackQueueImpl() {
// Prevent re-entrancy.
isFlushingSyncQueue = true;
let i = 0;
const previousLanePriority = getCurrentUpdateLanePriority();
try {
const isSync = true;
const queue = syncQueue;
setCurrentUpdateLanePriority(SyncLanePriority);
runWithPriority(ImmediatePriority, () => {
for (; i < queue.length; i++) {
let callback = queue[i];
do {
callback = callback(isSync);
} while (callback !== null);
if (decoupleUpdatePriorityFromScheduler) {
const previousLanePriority = getCurrentUpdateLanePriority();
try {
const isSync = true;
const queue = syncQueue;
setCurrentUpdateLanePriority(SyncLanePriority);
runWithPriority(ImmediatePriority, () => {
for (; i < queue.length; i++) {
let callback = queue[i];
do {
callback = callback(isSync);
} while (callback !== null);
}
});
syncQueue = null;
} catch (error) {
// If something throws, leave the remaining callbacks on the queue.
if (syncQueue !== null) {
syncQueue = syncQueue.slice(i + 1);
}
});
syncQueue = null;
} catch (error) {
// If something throws, leave the remaining callbacks on the queue.
if (syncQueue !== null) {
syncQueue = syncQueue.slice(i + 1);
// Resume flushing in the next tick
Scheduler_scheduleCallback(
Scheduler_ImmediatePriority,
flushSyncCallbackQueue,
);
throw error;
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
isFlushingSyncQueue = false;
}
} else {
try {
const isSync = true;
const queue = syncQueue;
runWithPriority(ImmediatePriority, () => {
for (; i < queue.length; i++) {
let callback = queue[i];
do {
callback = callback(isSync);
} while (callback !== null);
}
});
syncQueue = null;
} catch (error) {
// If something throws, leave the remaining callbacks on the queue.
if (syncQueue !== null) {
syncQueue = syncQueue.slice(i + 1);
}
// Resume flushing in the next tick
Scheduler_scheduleCallback(
Scheduler_ImmediatePriority,
flushSyncCallbackQueue,
);
throw error;
} finally {
isFlushingSyncQueue = false;
}
// Resume flushing in the next tick
Scheduler_scheduleCallback(
Scheduler_ImmediatePriority,
flushSyncCallbackQueue,
);
throw error;
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
isFlushingSyncQueue = false;
}
}
}
@@ -13,7 +13,10 @@ import type {ReactPriorityLevel} from './ReactInternalTypes';
// CommonJS interop named imports.
import * as Scheduler from 'scheduler';
import {__interactionsRef} from 'scheduler/tracing';
import {enableSchedulerTracing} from 'shared/ReactFeatureFlags';
import {
enableSchedulerTracing,
decoupleUpdatePriorityFromScheduler,
} from 'shared/ReactFeatureFlags';
import invariant from 'shared/invariant';
import {
SyncLanePriority,
@@ -176,34 +179,63 @@ function flushSyncCallbackQueueImpl() {
// Prevent re-entrancy.
isFlushingSyncQueue = true;
let i = 0;
const previousLanePriority = getCurrentUpdateLanePriority();
try {
const isSync = true;
const queue = syncQueue;
setCurrentUpdateLanePriority(SyncLanePriority);
runWithPriority(ImmediatePriority, () => {
for (; i < queue.length; i++) {
let callback = queue[i];
do {
callback = callback(isSync);
} while (callback !== null);
if (decoupleUpdatePriorityFromScheduler) {
const previousLanePriority = getCurrentUpdateLanePriority();
try {
const isSync = true;
const queue = syncQueue;
setCurrentUpdateLanePriority(SyncLanePriority);
runWithPriority(ImmediatePriority, () => {
for (; i < queue.length; i++) {
let callback = queue[i];
do {
callback = callback(isSync);
} while (callback !== null);
}
});
syncQueue = null;
} catch (error) {
// If something throws, leave the remaining callbacks on the queue.
if (syncQueue !== null) {
syncQueue = syncQueue.slice(i + 1);
}
});
syncQueue = null;
} catch (error) {
// If something throws, leave the remaining callbacks on the queue.
if (syncQueue !== null) {
syncQueue = syncQueue.slice(i + 1);
// Resume flushing in the next tick
Scheduler_scheduleCallback(
Scheduler_ImmediatePriority,
flushSyncCallbackQueue,
);
throw error;
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
isFlushingSyncQueue = false;
}
} else {
try {
const isSync = true;
const queue = syncQueue;
runWithPriority(ImmediatePriority, () => {
for (; i < queue.length; i++) {
let callback = queue[i];
do {
callback = callback(isSync);
} while (callback !== null);
}
});
syncQueue = null;
} catch (error) {
// If something throws, leave the remaining callbacks on the queue.
if (syncQueue !== null) {
syncQueue = syncQueue.slice(i + 1);
}
// Resume flushing in the next tick
Scheduler_scheduleCallback(
Scheduler_ImmediatePriority,
flushSyncCallbackQueue,
);
throw error;
} finally {
isFlushingSyncQueue = false;
}
// Resume flushing in the next tick
Scheduler_scheduleCallback(
Scheduler_ImmediatePriority,
flushSyncCallbackQueue,
);
throw error;
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
isFlushingSyncQueue = false;
}
}
}