[Perf] Introduce onFullyIdle to respect heavy animations

This commit is contained in:
Alexander Zinchuk 2024-09-06 15:42:25 +02:00
parent 4399c4fa8d
commit cfe7446d93
3 changed files with 35 additions and 16 deletions

View File

@ -28,7 +28,7 @@ import {
compact, pick, pickTruthy, unique,
} from '../util/iteratees';
import { encryptSession } from '../util/passcode';
import { onBeforeUnload, onIdle, throttle } from '../util/schedulers';
import { onBeforeUnload, throttle } from '../util/schedulers';
import { hasStoredSession } from '../util/sessions';
import { isUserId } from './helpers';
import { addActionHandler, getGlobal } from './index';
@ -44,11 +44,11 @@ import {
} from './selectors';
import { getIsMobile } from '../hooks/useAppLayout';
import { isHeavyAnimating } from '../hooks/useHeavyAnimationCheck';
import { isHeavyAnimating, onFullyIdle } from '../hooks/useHeavyAnimationCheck';
const UPDATE_THROTTLE = 5000;
const updateCacheThrottled = throttle(() => onIdle(() => updateCache()), UPDATE_THROTTLE, false);
const updateCacheThrottled = throttle(() => onFullyIdle(() => updateCache()), UPDATE_THROTTLE, false);
const updateCacheForced = () => updateCache(true);
let isCaching = false;

View File

@ -2,7 +2,10 @@ import {
useCallback, useEffect, useMemo, useRef,
} from '../lib/teact/teact';
import { requestMeasure } from '../lib/fasterdom/fasterdom';
import { createCallbackManager } from '../util/callbacks';
import { onIdle } from '../util/schedulers';
import { createSignal } from '../util/signals';
import useLastCallback from './useLastCallback';
// Make sure to end even if end callback was not called (which was some hardly-reproducible bug)
@ -12,13 +15,16 @@ const startCallbacks = createCallbackManager();
const endCallbacks = createCallbackManager();
let timeout: number | undefined;
let isAnimating = false;
const useHeavyAnimationCheck = (
const [getIsAnimating, setIsAnimating] = createSignal(false);
export const getIsHeavyAnimating = getIsAnimating;
export default function useHeavyAnimationCheck(
onStart?: AnyToVoidFunction,
onEnd?: AnyToVoidFunction,
isDisabled = false,
) => {
) {
const lastOnStart = useLastCallback(onStart);
const lastOnEnd = useLastCallback(onEnd);
@ -27,7 +33,7 @@ const useHeavyAnimationCheck = (
return undefined;
}
if (isAnimating) {
if (getIsAnimating()) {
lastOnStart();
}
@ -39,8 +45,9 @@ const useHeavyAnimationCheck = (
startCallbacks.removeCallback(lastOnStart);
};
}, [isDisabled, lastOnEnd, lastOnStart]);
};
}
// TODO → `onFullyIdle`?
export function useThrottleForHeavyAnimation<T extends AnyToVoidFunction>(afterHeavyAnimation: T, deps: unknown[]) {
// eslint-disable-next-line react-hooks-static-deps/exhaustive-deps
const fnMemo = useCallback(afterHeavyAnimation, deps);
@ -50,7 +57,7 @@ export function useThrottleForHeavyAnimation<T extends AnyToVoidFunction>(afterH
return useMemo(() => {
return (...args: Parameters<T>) => {
if (!isScheduledRef.current) {
if (!isAnimating) {
if (!getIsAnimating()) {
fnMemo(...args);
return;
}
@ -68,12 +75,12 @@ export function useThrottleForHeavyAnimation<T extends AnyToVoidFunction>(afterH
}
export function isHeavyAnimating() {
return isAnimating;
return getIsAnimating();
}
export function dispatchHeavyAnimationEvent(duration = AUTO_END_TIMEOUT) {
if (!isAnimating) {
isAnimating = true;
if (!getIsAnimating()) {
setIsAnimating(true);
startCallbacks.runCallbacks();
}
@ -89,7 +96,7 @@ export function dispatchHeavyAnimationEvent(duration = AUTO_END_TIMEOUT) {
timeout = undefined;
}
isAnimating = false;
setIsAnimating(false);
endCallbacks.runCallbacks();
}
@ -98,4 +105,14 @@ export function dispatchHeavyAnimationEvent(duration = AUTO_END_TIMEOUT) {
return onEnd;
}
export default useHeavyAnimationCheck;
export function onFullyIdle(cb: NoneToVoidFunction, idleTimeout?: number) {
onIdle(() => {
if (getIsAnimating()) {
requestMeasure(() => {
onFullyIdle(cb, idleTimeout);
});
} else {
cb();
}
}, idleTimeout);
}

View File

@ -21,7 +21,9 @@ import {
import arePropsShallowEqual from './arePropsShallowEqual';
import { createCallbackManager } from './callbacks';
import { areSortedArraysEqual, unique } from './iteratees';
import { onIdle, throttle } from './schedulers';
import { throttle } from './schedulers';
import { onFullyIdle } from '../hooks/useHeavyAnimationCheck';
interface FolderSummary {
id: number;
@ -112,7 +114,7 @@ if (DEBUG) {
}
const updateFolderManagerThrottled = throttle(() => {
onIdle(() => {
onFullyIdle(() => {
updateFolderManager(getGlobal());
});
}, UPDATE_THROTTLE);