[Perf] Introduce onFullyIdle to respect heavy animations
This commit is contained in:
parent
4399c4fa8d
commit
cfe7446d93
@ -28,7 +28,7 @@ import {
|
|||||||
compact, pick, pickTruthy, unique,
|
compact, pick, pickTruthy, unique,
|
||||||
} from '../util/iteratees';
|
} from '../util/iteratees';
|
||||||
import { encryptSession } from '../util/passcode';
|
import { encryptSession } from '../util/passcode';
|
||||||
import { onBeforeUnload, onIdle, throttle } from '../util/schedulers';
|
import { onBeforeUnload, throttle } from '../util/schedulers';
|
||||||
import { hasStoredSession } from '../util/sessions';
|
import { hasStoredSession } from '../util/sessions';
|
||||||
import { isUserId } from './helpers';
|
import { isUserId } from './helpers';
|
||||||
import { addActionHandler, getGlobal } from './index';
|
import { addActionHandler, getGlobal } from './index';
|
||||||
@ -44,11 +44,11 @@ import {
|
|||||||
} from './selectors';
|
} from './selectors';
|
||||||
|
|
||||||
import { getIsMobile } from '../hooks/useAppLayout';
|
import { getIsMobile } from '../hooks/useAppLayout';
|
||||||
import { isHeavyAnimating } from '../hooks/useHeavyAnimationCheck';
|
import { isHeavyAnimating, onFullyIdle } from '../hooks/useHeavyAnimationCheck';
|
||||||
|
|
||||||
const UPDATE_THROTTLE = 5000;
|
const UPDATE_THROTTLE = 5000;
|
||||||
|
|
||||||
const updateCacheThrottled = throttle(() => onIdle(() => updateCache()), UPDATE_THROTTLE, false);
|
const updateCacheThrottled = throttle(() => onFullyIdle(() => updateCache()), UPDATE_THROTTLE, false);
|
||||||
const updateCacheForced = () => updateCache(true);
|
const updateCacheForced = () => updateCache(true);
|
||||||
|
|
||||||
let isCaching = false;
|
let isCaching = false;
|
||||||
|
|||||||
@ -2,7 +2,10 @@ import {
|
|||||||
useCallback, useEffect, useMemo, useRef,
|
useCallback, useEffect, useMemo, useRef,
|
||||||
} from '../lib/teact/teact';
|
} from '../lib/teact/teact';
|
||||||
|
|
||||||
|
import { requestMeasure } from '../lib/fasterdom/fasterdom';
|
||||||
import { createCallbackManager } from '../util/callbacks';
|
import { createCallbackManager } from '../util/callbacks';
|
||||||
|
import { onIdle } from '../util/schedulers';
|
||||||
|
import { createSignal } from '../util/signals';
|
||||||
import useLastCallback from './useLastCallback';
|
import useLastCallback from './useLastCallback';
|
||||||
|
|
||||||
// Make sure to end even if end callback was not called (which was some hardly-reproducible bug)
|
// 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();
|
const endCallbacks = createCallbackManager();
|
||||||
|
|
||||||
let timeout: number | undefined;
|
let timeout: number | undefined;
|
||||||
let isAnimating = false;
|
|
||||||
|
|
||||||
const useHeavyAnimationCheck = (
|
const [getIsAnimating, setIsAnimating] = createSignal(false);
|
||||||
|
|
||||||
|
export const getIsHeavyAnimating = getIsAnimating;
|
||||||
|
|
||||||
|
export default function useHeavyAnimationCheck(
|
||||||
onStart?: AnyToVoidFunction,
|
onStart?: AnyToVoidFunction,
|
||||||
onEnd?: AnyToVoidFunction,
|
onEnd?: AnyToVoidFunction,
|
||||||
isDisabled = false,
|
isDisabled = false,
|
||||||
) => {
|
) {
|
||||||
const lastOnStart = useLastCallback(onStart);
|
const lastOnStart = useLastCallback(onStart);
|
||||||
const lastOnEnd = useLastCallback(onEnd);
|
const lastOnEnd = useLastCallback(onEnd);
|
||||||
|
|
||||||
@ -27,7 +33,7 @@ const useHeavyAnimationCheck = (
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isAnimating) {
|
if (getIsAnimating()) {
|
||||||
lastOnStart();
|
lastOnStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,8 +45,9 @@ const useHeavyAnimationCheck = (
|
|||||||
startCallbacks.removeCallback(lastOnStart);
|
startCallbacks.removeCallback(lastOnStart);
|
||||||
};
|
};
|
||||||
}, [isDisabled, lastOnEnd, lastOnStart]);
|
}, [isDisabled, lastOnEnd, lastOnStart]);
|
||||||
};
|
}
|
||||||
|
|
||||||
|
// TODO → `onFullyIdle`?
|
||||||
export function useThrottleForHeavyAnimation<T extends AnyToVoidFunction>(afterHeavyAnimation: T, deps: unknown[]) {
|
export function useThrottleForHeavyAnimation<T extends AnyToVoidFunction>(afterHeavyAnimation: T, deps: unknown[]) {
|
||||||
// eslint-disable-next-line react-hooks-static-deps/exhaustive-deps
|
// eslint-disable-next-line react-hooks-static-deps/exhaustive-deps
|
||||||
const fnMemo = useCallback(afterHeavyAnimation, deps);
|
const fnMemo = useCallback(afterHeavyAnimation, deps);
|
||||||
@ -50,7 +57,7 @@ export function useThrottleForHeavyAnimation<T extends AnyToVoidFunction>(afterH
|
|||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
return (...args: Parameters<T>) => {
|
return (...args: Parameters<T>) => {
|
||||||
if (!isScheduledRef.current) {
|
if (!isScheduledRef.current) {
|
||||||
if (!isAnimating) {
|
if (!getIsAnimating()) {
|
||||||
fnMemo(...args);
|
fnMemo(...args);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -68,12 +75,12 @@ export function useThrottleForHeavyAnimation<T extends AnyToVoidFunction>(afterH
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function isHeavyAnimating() {
|
export function isHeavyAnimating() {
|
||||||
return isAnimating;
|
return getIsAnimating();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function dispatchHeavyAnimationEvent(duration = AUTO_END_TIMEOUT) {
|
export function dispatchHeavyAnimationEvent(duration = AUTO_END_TIMEOUT) {
|
||||||
if (!isAnimating) {
|
if (!getIsAnimating()) {
|
||||||
isAnimating = true;
|
setIsAnimating(true);
|
||||||
startCallbacks.runCallbacks();
|
startCallbacks.runCallbacks();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +96,7 @@ export function dispatchHeavyAnimationEvent(duration = AUTO_END_TIMEOUT) {
|
|||||||
timeout = undefined;
|
timeout = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
isAnimating = false;
|
setIsAnimating(false);
|
||||||
endCallbacks.runCallbacks();
|
endCallbacks.runCallbacks();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,4 +105,14 @@ export function dispatchHeavyAnimationEvent(duration = AUTO_END_TIMEOUT) {
|
|||||||
return onEnd;
|
return onEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default useHeavyAnimationCheck;
|
export function onFullyIdle(cb: NoneToVoidFunction, idleTimeout?: number) {
|
||||||
|
onIdle(() => {
|
||||||
|
if (getIsAnimating()) {
|
||||||
|
requestMeasure(() => {
|
||||||
|
onFullyIdle(cb, idleTimeout);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
}, idleTimeout);
|
||||||
|
}
|
||||||
|
|||||||
@ -21,7 +21,9 @@ import {
|
|||||||
import arePropsShallowEqual from './arePropsShallowEqual';
|
import arePropsShallowEqual from './arePropsShallowEqual';
|
||||||
import { createCallbackManager } from './callbacks';
|
import { createCallbackManager } from './callbacks';
|
||||||
import { areSortedArraysEqual, unique } from './iteratees';
|
import { areSortedArraysEqual, unique } from './iteratees';
|
||||||
import { onIdle, throttle } from './schedulers';
|
import { throttle } from './schedulers';
|
||||||
|
|
||||||
|
import { onFullyIdle } from '../hooks/useHeavyAnimationCheck';
|
||||||
|
|
||||||
interface FolderSummary {
|
interface FolderSummary {
|
||||||
id: number;
|
id: number;
|
||||||
@ -112,7 +114,7 @@ if (DEBUG) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const updateFolderManagerThrottled = throttle(() => {
|
const updateFolderManagerThrottled = throttle(() => {
|
||||||
onIdle(() => {
|
onFullyIdle(() => {
|
||||||
updateFolderManager(getGlobal());
|
updateFolderManager(getGlobal());
|
||||||
});
|
});
|
||||||
}, UPDATE_THROTTLE);
|
}, UPDATE_THROTTLE);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user