178
179
type ExecutionContext = number;
180
181
-const NoContext = /* */ 0b00000;
182
-const BatchedContext = /* */ 0b00001;
183
-const EventContext = /* */ 0b00010;
184
-const LegacyUnbatchedContext = /* */ 0b00100;
185
-const RenderContext = /* */ 0b01000;
186
-const CommitContext = /* */ 0b10000;
181
+const NoContext = /* */ 0b000000;
182
+const BatchedContext = /* */ 0b000001;
183
+const EventContext = /* */ 0b000010;
184
+const DiscreteEventContext = /* */ 0b000100;
185
+const LegacyUnbatchedContext = /* */ 0b001000;
186
+const RenderContext = /* */ 0b010000;
187
+const CommitContext = /* */ 0b100000;
188
189
type RootExitStatus = 0 | 1 | 2 | 3 | 4;
190
const RootIncomplete = 0;
364
checkForInterruption(fiber, expirationTime);
365
recordScheduleUpdate();
366
367
+ // TODO: computeExpirationForFiber also reads the priority. Pass the
368
+ // priority as an argument to that function and this one.
369
+ const priorityLevel = getCurrentPriorityLevel();
370
+
371
if (expirationTime === Sync) {
372
if (
373
// Check if we're inside unbatchedUpdates
397
}
398
}
399
} else {
395
- // TODO: computeExpirationForFiber also reads the priority. Pass the
396
- // priority as an argument to that function and this one.
397
- const priorityLevel = getCurrentPriorityLevel();
398
- if (priorityLevel === UserBlockingPriority) {
399
- // This is the result of a discrete event. Track the lowest priority
400
- // discrete update per root so we can flush them early, if needed.
401
- if (rootsWithPendingDiscreteUpdates === null) {
402
- rootsWithPendingDiscreteUpdates = new Map([[root, expirationTime]]);
403
- } else {
404
- const lastDiscreteTime = rootsWithPendingDiscreteUpdates.get(root);
405
- if (
406
- lastDiscreteTime === undefined ||
407
- lastDiscreteTime > expirationTime
408
- ) {
409
- rootsWithPendingDiscreteUpdates.set(root, expirationTime);
410
- }
400
+ scheduleCallbackForRoot(root, priorityLevel, expirationTime);
401
+ }
402
+
403
+ if (
404
+ (executionContext & DiscreteEventContext) !== NoContext &&
405
+ // Only updates at user-blocking priority or greater are considered
406
+ // discrete, even inside a discrete event.
407
+ (priorityLevel === UserBlockingPriority ||
408
+ priorityLevel === ImmediatePriority)
409
+ ) {
410
+ // This is the result of a discrete event. Track the lowest priority
411
+ // discrete update per root so we can flush them early, if needed.
412
+ if (rootsWithPendingDiscreteUpdates === null) {
413
+ rootsWithPendingDiscreteUpdates = new Map([[root, expirationTime]]);
414
+ } else {
415
+ const lastDiscreteTime = rootsWithPendingDiscreteUpdates.get(root);
416
+ if (lastDiscreteTime === undefined || lastDiscreteTime > expirationTime) {
417
+ rootsWithPendingDiscreteUpdates.set(root, expirationTime);
418
}
419
}
413
- scheduleCallbackForRoot(root, priorityLevel, expirationTime);
420
}
421
}
422
export const scheduleWork = scheduleUpdateOnFiber;
629
return runWithPriority(NormalPriority, fn);
630
}
631
626
-export function discreteUpdates<A, B, C, R>(
627
- fn: (A, B, C) => R,
628
- a: A,
629
- b: B,
630
- c: C,
631
-): R {
632
- return runWithPriority(UserBlockingPriority, fn.bind(null, a, b, c));
633
-}
634
-
632
export function syncUpdates<A, B, C, R>(
633
fn: (A, B, C) => R,
634
a: A,
680
}
681
}
682
683
+export function discreteUpdates<A, B, C, R>(
684
+ fn: (A, B, C) => R,
685
+ a: A,
686
+ b: B,
687
+ c: C,
688
+): R {
689
+ const prevExecutionContext = executionContext;
690
+ executionContext |= DiscreteEventContext;
691
+ try {
692
+ // Should this
693
+ return runWithPriority(UserBlockingPriority, fn.bind(null, a, b, c));
694
+ } finally {
695
+ executionContext = prevExecutionContext;
696
+ if (executionContext === NoContext) {
697
+ // Flush the immediate callbacks that were scheduled during this batch
698
+ flushSyncCallbackQueue();
699
+ }
700
+ }
701
+}
702
+
703
export function unbatchedUpdates<A, R>(fn: (a: A) => R, a: A): R {
704
const prevExecutionContext = executionContext;
705
executionContext &= ~BatchedContext;