[Perf] useHeavyAnimationCheck: Support multiple heavy animations

This commit is contained in:
Alexander Zinchuk 2024-09-06 15:42:39 +02:00
parent ec6a28baf6
commit 79fca8ea1b
3 changed files with 29 additions and 19 deletions

View File

@ -245,6 +245,7 @@ function Transition({
requestMutation(() => {
if (activeKey !== currentKeyRef.current) {
dispatchHeavyAnimationStop();
return;
}
@ -472,6 +473,7 @@ function performSlideOptimized(
requestMutation(() => {
if (activeKey !== currentKeyRef.current) {
dispatchHeavyAnimationStop();
return;
}

View File

@ -14,7 +14,7 @@ const AUTO_END_TIMEOUT = 1000;
const startCallbacks = createCallbackManager();
const endCallbacks = createCallbackManager();
let timeout: number | undefined;
let counter = 0;
const [getIsAnimating, setIsAnimating] = createSignal(false);
@ -79,29 +79,31 @@ export function isHeavyAnimating() {
}
export function dispatchHeavyAnimationEvent(duration = AUTO_END_TIMEOUT) {
if (!getIsAnimating()) {
counter++;
if (counter === 1) {
setIsAnimating(true);
startCallbacks.runCallbacks();
}
if (timeout) {
clearTimeout(timeout);
timeout = undefined;
}
const timeout = window.setTimeout(onEnd, duration);
let hasEnded = false;
// Race condition may happen if another `dispatchHeavyAnimationEvent` is called before `onEnd`
function onEnd() {
if (timeout) {
clearTimeout(timeout);
timeout = undefined;
if (hasEnded) return;
hasEnded = true;
clearTimeout(timeout);
counter--;
if (counter === 0) {
setIsAnimating(false);
endCallbacks.runCallbacks();
}
setIsAnimating(false);
endCallbacks.runCallbacks();
}
timeout = window.setTimeout(onEnd, duration);
return onEnd;
}

View File

@ -20,6 +20,7 @@ type Params = Parameters<typeof createMutateFunction>;
let isAnimating = false;
let currentArgs: Parameters<typeof createMutateFunction> | undefined;
let onHeavyAnimationStop: NoneToVoidFunction | undefined;
export default function animateScroll(...args: Params | [...Params, boolean]) {
currentArgs = args.slice(0, 8) as Params;
@ -117,15 +118,18 @@ function createMutateFunction(
return;
}
isAnimating = true;
const transition = absPath <= FAST_SMOOTH_SHORT_TRANSITION_MAX_DISTANCE ? shortTransition : longTransition;
const duration = forceDuration || (
FAST_SMOOTH_MIN_DURATION
+ (absPath / FAST_SMOOTH_MAX_DISTANCE) * (FAST_SMOOTH_MAX_DURATION - FAST_SMOOTH_MIN_DURATION)
);
const startAt = Date.now();
const onHeavyAnimationStop = dispatchHeavyAnimationEvent();
isAnimating = true;
const prevOnHeavyAnimationStop = onHeavyAnimationStop;
onHeavyAnimationStop = dispatchHeavyAnimationEvent();
prevOnHeavyAnimationStop?.();
animateSingle(() => {
const t = Math.min((Date.now() - startAt) / duration, 1);
@ -138,7 +142,9 @@ function createMutateFunction(
if (!isAnimating) {
currentArgs = undefined;
onHeavyAnimationStop();
onHeavyAnimationStop!();
onHeavyAnimationStop = undefined;
}
return isAnimating;