26
enableSchedulerTracing,
27
warnAboutUnmockedScheduler,
28
deferRenderPhaseUpdateToNextBatch,
29
+ decoupleUpdatePriorityFromScheduler,
30
} from 'shared/ReactFeatureFlags';
31
import ReactSharedInternals from 'shared/ReactSharedInternals';
32
import invariant from 'shared/invariant';
114
InputDiscreteLanePriority,
115
TransitionShortLanePriority,
116
TransitionLongLanePriority,
117
+ DefaultLanePriority,
118
NoLanes,
119
NoLane,
120
SyncLane,
132
hasUpdatePriority,
133
getNextLanes,
134
returnNextLanesPriority,
135
+ setCurrentUpdateLanePriority,
136
+ getCurrentUpdateLanePriority,
137
markStarvedLanesAsExpired,
138
getLanesToRetrySynchronouslyOnError,
139
markRootUpdated,
398
currentEventWipLanes = workInProgressRootIncludedLanes;
399
}
400
397
- let lane;
401
if (suspenseConfig !== null) {
402
// Use the size of the timeout as a heuristic to prioritize shorter
403
// transitions over longer ones.
415
: NoLanes;
416
}
417
415
- lane = findTransitionLane(
418
+ return findTransitionLane(
419
transitionLanePriority,
420
currentEventWipLanes,
421
currentEventPendingLanes,
422
);
423
+ }
424
+
425
+ // TODO: Remove this dependency on the Scheduler priority.
426
+ // To do that, we're replacing it with an update lane priority.
427
+ const schedulerPriority = getCurrentPriorityLevel();
428
+
429
+ // The old behavior was using the priority level of the Scheduler.
430
+ // This couples React to the Scheduler internals, so we're replacing it
431
+ // with the currentUpdateLanePriority above. As an example of how this
432
+ // could be problematic, if we're not inside `Scheduler.runWithPriority`,
433
+ // then we'll get the priority of the current running Scheduler task,
434
+ // which is probably not what we want.
435
+ let lane;
436
+ if (
437
+ // TODO: Temporary. We're removing the concept of discrete updates.
438
+ (executionContext & DiscreteEventContext) !== NoContext &&
439
+ schedulerPriority === UserBlockingSchedulerPriority
440
+ ) {
441
+ lane = findUpdateLane(InputDiscreteLanePriority, currentEventWipLanes);
442
} else {
421
- // TODO: If we're not inside `runWithPriority`, this returns the priority
422
- // of the currently running task. That's probably not what we want.
423
- const schedulerPriority = getCurrentPriorityLevel();
443
+ const schedulerLanePriority = schedulerPriorityToLanePriority(
444
+ schedulerPriority,
445
+ );
446
425
- if (
426
- // TODO: Temporary. We're removing the concept of discrete updates.
427
- (executionContext & DiscreteEventContext) !== NoContext &&
428
- schedulerPriority === UserBlockingSchedulerPriority
429
- ) {
430
- lane = findUpdateLane(InputDiscreteLanePriority, currentEventWipLanes);
431
- } else {
432
- const lanePriority = schedulerPriorityToLanePriority(schedulerPriority);
433
- lane = findUpdateLane(lanePriority, currentEventWipLanes);
447
+ if (decoupleUpdatePriorityFromScheduler) {
448
+ // In the new strategy, we will track the current update lane priority
449
+ // inside React and use that priority to select a lane for this update.
450
+ // For now, we're just logging when they're different so we can assess.
451
+ const currentUpdateLanePriority = getCurrentUpdateLanePriority();
452
+
453
+ if (
454
+ schedulerLanePriority !== currentUpdateLanePriority &&
455
+ currentUpdateLanePriority !== NoLanePriority
456
+ ) {
457
+ if (__DEV__) {
458
+ console.error(
459
+ 'Expected current scheduler lane priority %s to match current update lane priority %s',
460
+ schedulerLanePriority,
461
+ currentUpdateLanePriority,
462
+ );
463
+ }
464
+ }
465
}
466
+
467
+ lane = findUpdateLane(schedulerLanePriority, currentEventWipLanes);
468
}
469
470
return lane;
1101
1102
export function deferredUpdates<A>(fn: () => A): A {
1103
// TODO: Remove in favor of Scheduler.next
1071
- return runWithPriority(NormalSchedulerPriority, fn);
1104
+ const previousLanePriority = getCurrentUpdateLanePriority();
1105
+ try {
1106
+ setCurrentUpdateLanePriority(DefaultLanePriority);
1107
+ return runWithPriority(NormalSchedulerPriority, fn);
1108
+ } finally {
1109
+ setCurrentUpdateLanePriority(previousLanePriority);
1110
+ }
1111
}
1112
1113
function flushPendingDiscreteUpdates() {
1162
): R {
1163
const prevExecutionContext = executionContext;
1164
executionContext |= DiscreteEventContext;
1165
+ const previousLanePriority = getCurrentUpdateLanePriority();
1166
try {
1167
+ setCurrentUpdateLanePriority(InputDiscreteLanePriority);
1168
// Should this
1169
return runWithPriority(
1170
UserBlockingSchedulerPriority,
1171
fn.bind(null, a, b, c, d),
1172
);
1173
} finally {
1174
+ setCurrentUpdateLanePriority(previousLanePriority);
1175
executionContext = prevExecutionContext;
1176
if (executionContext === NoContext) {
1177
// Flush the immediate callbacks that were scheduled during this batch
1208
return fn(a);
1209
}
1210
executionContext |= BatchedContext;
1211
+ const previousLanePriority = getCurrentUpdateLanePriority();
1212
try {
1213
+ setCurrentUpdateLanePriority(SyncLanePriority);
1214
if (fn) {
1215
return runWithPriority(ImmediateSchedulerPriority, fn.bind(null, a));
1216
} else {
1217
return (undefined: $FlowFixMe);
1218
}
1219
} finally {
1220
+ setCurrentUpdateLanePriority(previousLanePriority);
1221
executionContext = prevExecutionContext;
1222
// Flush the immediate callbacks that were scheduled during this batch.
1223
// Note that this will happen even if batchedUpdates is higher up
1229
export function flushControlled(fn: () => mixed): void {
1230
const prevExecutionContext = executionContext;
1231
executionContext |= BatchedContext;
1232
+ const previousLanePriority = getCurrentUpdateLanePriority();
1233
try {
1234
+ setCurrentUpdateLanePriority(SyncLanePriority);
1235
runWithPriority(ImmediateSchedulerPriority, fn);
1236
} finally {
1237
+ setCurrentUpdateLanePriority(previousLanePriority);
1238
executionContext = prevExecutionContext;
1239
if (executionContext === NoContext) {
1240
// Flush the immediate callbacks that were scheduled during this batch
1915
}
1916
1917
if (firstEffect !== null) {
1918
+ const previousLanePriority = getCurrentUpdateLanePriority();
1919
+ setCurrentUpdateLanePriority(SyncLanePriority);
1920
+
1921
const prevExecutionContext = executionContext;
1922
executionContext |= CommitContext;
1923
const prevInteractions = pushInteractions(root);
2038
popInteractions(((prevInteractions: any): Set<Interaction>));
2039
}
2040
executionContext = prevExecutionContext;
2041
+
2042
+ // Reset the priority to the previous non-sync value.
2043
+ setCurrentUpdateLanePriority(previousLanePriority);
2044
} else {
2045
// No effects.
2046
root.current = finishedWork;
2303
? NormalSchedulerPriority
2304
: pendingPassiveEffectsRenderPriority;
2305
pendingPassiveEffectsRenderPriority = NoSchedulerPriority;
2252
- return runWithPriority(priorityLevel, flushPassiveEffectsImpl);
2306
+ const previousLanePriority = getCurrentUpdateLanePriority();
2307
+ try {
2308
+ setCurrentUpdateLanePriority(
2309
+ schedulerPriorityToLanePriority(priorityLevel),
2310
+ );
2311
+ return runWithPriority(priorityLevel, flushPassiveEffectsImpl);
2312
+ } finally {
2313
+ setCurrentUpdateLanePriority(previousLanePriority);
2314
+ }
2315
}
2316
}
2317