Skip to content

Commit 16b4d29

Browse files
rickhanloniityao1
authored andcommitted
Add frame-end scheduling (V3)
Use frameAligned for DefaultUpdate Modifications after rebasing onto batching lanes
1 parent 07cc4a0 commit 16b4d29

22 files changed

+761
-214
lines changed

packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import {getCurrentRootHostContainer} from 'react-reconciler/src/ReactFiberHostCo
3333
import {DefaultEventPriority} from 'react-reconciler/src/ReactEventPriorities';
3434
// TODO: Remove this deep import when we delete the legacy root API
3535
import {ConcurrentMode, NoMode} from 'react-reconciler/src/ReactTypeOfMode';
36+
import * as Scheduler from 'scheduler';
3637

3738
import hasOwnProperty from 'shared/hasOwnProperty';
3839
import {checkAttributeStringCoercion} from 'shared/CheckStringCoercion';
@@ -623,6 +624,11 @@ const localRequestAnimationFrame =
623624
typeof requestAnimationFrame === 'function'
624625
? requestAnimationFrame
625626
: scheduleTimeout;
627+
const localCancelAnimationFrame =
628+
typeof window !== 'undefined' &&
629+
typeof window.cancelAnimationFrame === 'function'
630+
? window.cancelAnimationFrame
631+
: cancelTimeout;
626632

627633
export function getInstanceFromNode(node: HTMLElement): null | Object {
628634
return getClosestInstanceFromNode(node) || null;
@@ -668,6 +674,68 @@ function handleErrorInNextTick(error: any) {
668674
});
669675
}
670676

677+
// -------------------
678+
// Animation Frame
679+
// -------------------
680+
export const supportsFrameAlignedTask = true;
681+
682+
type FrameAlignedTask = {|
683+
rafNode: AnimationFrameID,
684+
schedulerNode: number | null,
685+
task: Function,
686+
|};
687+
688+
let currentTask: FrameAlignedTask | null = null;
689+
function performFrameAlignedWork() {
690+
if (currentTask != null) {
691+
const currentTaskForFlow = currentTask;
692+
const task = currentTask.task;
693+
localCancelAnimationFrame(currentTaskForFlow.rafNode);
694+
if (currentTaskForFlow.schedulerNode !== null) {
695+
Scheduler.unstable_cancelCallback(currentTaskForFlow.schedulerNode);
696+
}
697+
currentTask = null;
698+
if (task != null) {
699+
task();
700+
}
701+
}
702+
}
703+
704+
export function scheduleFrameAlignedTask(task: any): any {
705+
if (currentTask === null) {
706+
const rafNode = localRequestAnimationFrame(performFrameAlignedWork);
707+
708+
const schedulerNode = Scheduler.unstable_scheduleCallback(
709+
Scheduler.unstable_NormalPriority,
710+
performFrameAlignedWork,
711+
);
712+
713+
currentTask = {
714+
rafNode,
715+
schedulerNode,
716+
task,
717+
};
718+
} else {
719+
currentTask.task = task;
720+
currentTask.schedulerNode = Scheduler.unstable_scheduleCallback(
721+
Scheduler.unstable_NormalPriority,
722+
performFrameAlignedWork,
723+
);
724+
}
725+
726+
return currentTask;
727+
}
728+
729+
export function cancelFrameAlignedTask(task: any) {
730+
if (task.schedulerNode) {
731+
Scheduler.unstable_cancelCallback(task.schedulerNode);
732+
task.schedulerNode = null;
733+
}
734+
// We don't cancel the rAF in case it gets re-used later.
735+
// But clear the task so if it fires and shouldn't run, it won't.
736+
task.task = null;
737+
}
738+
671739
// -------------------
672740
// Mutation
673741
// -------------------

0 commit comments

Comments
 (0)