Skip to content

Commit

Permalink
Use callback priority to determine cancellation
Browse files Browse the repository at this point in the history
  • Loading branch information
rickhanlonii committed Jan 27, 2021
1 parent bf6990a commit 43f8cc4
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 15 deletions.
29 changes: 22 additions & 7 deletions packages/react-reconciler/src/ReactFiberWorkLoop.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -716,29 +716,43 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) {
// Special case: There's nothing to work on.
if (existingCallbackNode !== null) {
cancelCallback(existingCallbackNode);
root.callbackNode = null;
root.callbackPriority = NoLanePriority;
}
root.callbackNode = null;
root.callbackPriority = NoLanePriority;
return;
}

// Check if there's an existing task. We may be able to reuse it.
if (existingCallbackNode !== null) {
const existingCallbackPriority = root.callbackPriority;
const existingCallbackPriority = root.callbackPriority;
if (
existingCallbackPriority !== NoLanePriority &&
existingCallbackPriority !== InputDiscreteLanePriority
) {
if (existingCallbackPriority === newCallbackPriority) {
// The priority hasn't changed. We can reuse the existing task. Exit.
return;
}
// The priority changed. Cancel the existing callback. We'll schedule a new
// one below.
cancelCallback(existingCallbackNode);

if (existingCallbackNode != null) {
// The priority changed. Cancel the existing callback.
// We'll schedule a new one below.
cancelCallback(existingCallbackNode);
} else {
// TODO: Temporary. This shouldn't happen, but remove after confirmed.
// Using console['error'] to evade Babel and ESLint
console['error'](
'Expected scheduled callback to exist. This error is likely caused by a bug in React. Please file an issue.',
);
}
}

// Schedule a new callback.
let newCallbackNode;
if (newCallbackPriority === SyncLanePriority) {
// Special case: Sync React callbacks are scheduled on a special
// internal queue

// TODO: After enableDiscreteEventMicroTasks lands, we can remove the fake node.
newCallbackNode = scheduleSyncCallback(
performSyncWorkOnRoot.bind(null, root),
);
Expand Down Expand Up @@ -1879,6 +1893,7 @@ function commitRootImpl(root, renderPriorityLevel) {
// commitRoot never returns a continuation; it always finishes synchronously.
// So we can clear these now to allow a new callback to be scheduled.
root.callbackNode = null;
root.callbackPriority = NoLanePriority;

// Update the first and last pending times on this root. The new first
// pending time is whatever is left on the root fiber.
Expand Down
29 changes: 22 additions & 7 deletions packages/react-reconciler/src/ReactFiberWorkLoop.old.js
Original file line number Diff line number Diff line change
Expand Up @@ -698,29 +698,43 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) {
// Special case: There's nothing to work on.
if (existingCallbackNode !== null) {
cancelCallback(existingCallbackNode);
root.callbackNode = null;
root.callbackPriority = NoLanePriority;
}
root.callbackNode = null;
root.callbackPriority = NoLanePriority;
return;
}

// Check if there's an existing task. We may be able to reuse it.
if (existingCallbackNode !== null) {
const existingCallbackPriority = root.callbackPriority;
const existingCallbackPriority = root.callbackPriority;
if (
existingCallbackPriority !== NoLanePriority &&
existingCallbackPriority !== InputDiscreteLanePriority
) {
if (existingCallbackPriority === newCallbackPriority) {
// The priority hasn't changed. We can reuse the existing task. Exit.
return;
}
// The priority changed. Cancel the existing callback. We'll schedule a new
// one below.
cancelCallback(existingCallbackNode);

if (existingCallbackNode != null) {
// The priority changed. Cancel the existing callback.
// We'll schedule a new one below.
cancelCallback(existingCallbackNode);
} else {
// TODO: Temporary. This shouldn't happen, but remove after confirmed.
// Using console['error'] to evade Babel and ESLint
console['error'](
'Expected scheduled callback to exist. This error is likely caused by a bug in React. Please file an issue.',
);
}
}

// Schedule a new callback.
let newCallbackNode;
if (newCallbackPriority === SyncLanePriority) {
// Special case: Sync React callbacks are scheduled on a special
// internal queue

// TODO: After enableDiscreteEventMicroTasks lands, we can remove the fake node.
newCallbackNode = scheduleSyncCallback(
performSyncWorkOnRoot.bind(null, root),
);
Expand Down Expand Up @@ -1859,6 +1873,7 @@ function commitRootImpl(root, renderPriorityLevel) {
// commitRoot never returns a continuation; it always finishes synchronously.
// So we can clear these now to allow a new callback to be scheduled.
root.callbackNode = null;
root.callbackPriority = NoLanePriority;

// Update the first and last pending times on this root. The new first
// pending time is whatever is left on the root fiber.
Expand Down
3 changes: 2 additions & 1 deletion scripts/error-codes/codes.json
Original file line number Diff line number Diff line change
Expand Up @@ -372,5 +372,6 @@
"381": "This feature is not supported by ReactSuspenseTestUtils.",
"382": "This query has received more parameters than the last time the same query was used. Always pass the exact number of parameters that the query needs.",
"383": "This query has received fewer parameters than the last time the same query was used. Always pass the exact number of parameters that the query needs.",
"384": "Refreshing the cache is not supported in Server Components."
"384": "Refreshing the cache is not supported in Server Components.",
"385": "Expected scheduled callback to exist. This error is likely caused by a bug in React. Please file an issue."
}

0 comments on commit 43f8cc4

Please sign in to comment.