[Perf] TeactN: Check for heavy animations
This commit is contained in:
parent
9d58257319
commit
ebf20fa013
2
src/@types/global.d.ts
vendored
2
src/@types/global.d.ts
vendored
@ -65,7 +65,7 @@ interface IWebpWorker extends Worker {
|
|||||||
|
|
||||||
interface Window {
|
interface Window {
|
||||||
ClipboardItem?: any;
|
ClipboardItem?: any;
|
||||||
requestIdleCallback: (cb: AnyToVoidFunction) => void;
|
requestIdleCallback: (cb: AnyToVoidFunction, options:{ timeout?: number }) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Clipboard { write?: any }
|
interface Clipboard { write?: any }
|
||||||
|
|||||||
@ -19,6 +19,7 @@ import {
|
|||||||
import captureKeyboardListeners from '../../../util/captureKeyboardListeners';
|
import captureKeyboardListeners from '../../../util/captureKeyboardListeners';
|
||||||
import useLayoutEffectWithPrevDeps from '../../../hooks/useLayoutEffectWithPrevDeps';
|
import useLayoutEffectWithPrevDeps from '../../../hooks/useLayoutEffectWithPrevDeps';
|
||||||
import useFlag from '../../../hooks/useFlag';
|
import useFlag from '../../../hooks/useFlag';
|
||||||
|
import { isHeavyAnimating } from '../../../hooks/useHeavyAnimationCheck';
|
||||||
import parseEmojiOnlyString from '../../common/helpers/parseEmojiOnlyString';
|
import parseEmojiOnlyString from '../../common/helpers/parseEmojiOnlyString';
|
||||||
import { isSelectionInsideInput } from './helpers/selection';
|
import { isSelectionInsideInput } from './helpers/selection';
|
||||||
import useLang from '../../../hooks/useLang';
|
import useLang from '../../../hooks/useLang';
|
||||||
@ -125,8 +126,7 @@ const MessageInput: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
}, [html]);
|
}, [html]);
|
||||||
|
|
||||||
const focusInput = useCallback(() => {
|
const focusInput = useCallback(() => {
|
||||||
// Avoid focusing during animation
|
if (isHeavyAnimating()) {
|
||||||
if (inputRef.current!.closest('.from, .to')) {
|
|
||||||
setTimeout(focusInput, FOCUS_DELAY_MS);
|
setTimeout(focusInput, FOCUS_DELAY_MS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,7 @@ import {
|
|||||||
DEFAULT_PLAYBACK_RATE,
|
DEFAULT_PLAYBACK_RATE,
|
||||||
} from '../config';
|
} from '../config';
|
||||||
import { IS_SINGLE_COLUMN_LAYOUT } from '../util/environment';
|
import { IS_SINGLE_COLUMN_LAYOUT } from '../util/environment';
|
||||||
import { ANIMATION_END_EVENT, ANIMATION_START_EVENT } from '../hooks/useHeavyAnimationCheck';
|
import { isHeavyAnimating } from '../hooks/useHeavyAnimationCheck';
|
||||||
import { pick } from '../util/iteratees';
|
import { pick } from '../util/iteratees';
|
||||||
import { selectCurrentMessageList } from '../modules/selectors';
|
import { selectCurrentMessageList } from '../modules/selectors';
|
||||||
import { hasStoredSession } from '../util/sessions';
|
import { hasStoredSession } from '../util/sessions';
|
||||||
@ -31,11 +31,8 @@ const UPDATE_THROTTLE = 5000;
|
|||||||
const updateCacheThrottled = throttle(() => onIdle(updateCache), UPDATE_THROTTLE, false);
|
const updateCacheThrottled = throttle(() => onIdle(updateCache), UPDATE_THROTTLE, false);
|
||||||
|
|
||||||
let isCaching = false;
|
let isCaching = false;
|
||||||
let isHeavyAnimating = false;
|
|
||||||
let unsubscribeFromBeforeUnload: NoneToVoidFunction | undefined;
|
let unsubscribeFromBeforeUnload: NoneToVoidFunction | undefined;
|
||||||
|
|
||||||
setupHeavyAnimationListeners();
|
|
||||||
|
|
||||||
export function initCache() {
|
export function initCache() {
|
||||||
if (GLOBAL_STATE_CACHE_DISABLED) {
|
if (GLOBAL_STATE_CACHE_DISABLED) {
|
||||||
return;
|
return;
|
||||||
@ -200,7 +197,7 @@ function migrateCache(cached: GlobalState, initialState: GlobalState) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateCache() {
|
function updateCache() {
|
||||||
if (!isCaching || isHeavyAnimating) {
|
if (!isCaching || isHeavyAnimating()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,12 +341,3 @@ function reduceGroupCalls(global: GlobalState): GlobalState['groupCalls'] {
|
|||||||
isFallbackConfirmOpen: undefined,
|
isFallbackConfirmOpen: undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupHeavyAnimationListeners() {
|
|
||||||
document.addEventListener(ANIMATION_START_EVENT, () => {
|
|
||||||
isHeavyAnimating = true;
|
|
||||||
});
|
|
||||||
document.addEventListener(ANIMATION_END_EVENT, () => {
|
|
||||||
isHeavyAnimating = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,12 +1,35 @@
|
|||||||
import { useEffect } from '../lib/teact/teact';
|
import { useEffect } from '../lib/teact/teact';
|
||||||
|
|
||||||
export const ANIMATION_START_EVENT = 'tt-event-heavy-animation-start';
|
const ANIMATION_START_EVENT = 'tt-event-heavy-animation-start';
|
||||||
export const ANIMATION_END_EVENT = 'tt-event-heavy-animation-end';
|
const ANIMATION_END_EVENT = 'tt-event-heavy-animation-end';
|
||||||
|
|
||||||
let timeout: number | undefined;
|
let timeout: number | undefined;
|
||||||
let isAnimating = false;
|
let isAnimating = false;
|
||||||
|
|
||||||
export const dispatchHeavyAnimationEvent = (duration?: number) => {
|
export default (
|
||||||
|
handleAnimationStart: AnyToVoidFunction,
|
||||||
|
handleAnimationEnd: AnyToVoidFunction,
|
||||||
|
) => {
|
||||||
|
useEffect(() => {
|
||||||
|
if (isAnimating) {
|
||||||
|
handleAnimationStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener(ANIMATION_START_EVENT, handleAnimationStart);
|
||||||
|
document.addEventListener(ANIMATION_END_EVENT, handleAnimationEnd);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener(ANIMATION_END_EVENT, handleAnimationEnd);
|
||||||
|
document.removeEventListener(ANIMATION_START_EVENT, handleAnimationStart);
|
||||||
|
};
|
||||||
|
}, [handleAnimationEnd, handleAnimationStart]);
|
||||||
|
};
|
||||||
|
|
||||||
|
export function isHeavyAnimating() {
|
||||||
|
return isAnimating;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function dispatchHeavyAnimationEvent(duration?: number) {
|
||||||
if (!isAnimating) {
|
if (!isAnimating) {
|
||||||
isAnimating = true;
|
isAnimating = true;
|
||||||
document.dispatchEvent(new Event(ANIMATION_START_EVENT));
|
document.dispatchEvent(new Event(ANIMATION_START_EVENT));
|
||||||
@ -29,23 +52,4 @@ export const dispatchHeavyAnimationEvent = (duration?: number) => {
|
|||||||
isAnimating = false;
|
isAnimating = false;
|
||||||
document.dispatchEvent(new Event(ANIMATION_END_EVENT));
|
document.dispatchEvent(new Event(ANIMATION_END_EVENT));
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
export default (
|
|
||||||
handleAnimationStart: AnyToVoidFunction,
|
|
||||||
handleAnimationEnd: AnyToVoidFunction,
|
|
||||||
) => {
|
|
||||||
useEffect(() => {
|
|
||||||
if (isAnimating) {
|
|
||||||
handleAnimationStart();
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener(ANIMATION_START_EVENT, handleAnimationStart);
|
|
||||||
document.addEventListener(ANIMATION_END_EVENT, handleAnimationEnd);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
document.removeEventListener(ANIMATION_END_EVENT, handleAnimationEnd);
|
|
||||||
document.removeEventListener(ANIMATION_START_EVENT, handleAnimationStart);
|
|
||||||
};
|
|
||||||
}, [handleAnimationEnd, handleAnimationStart]);
|
|
||||||
};
|
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import arePropsShallowEqual, { getUnequalProps } from '../../util/arePropsShallo
|
|||||||
import { orderBy } from '../../util/iteratees';
|
import { orderBy } from '../../util/iteratees';
|
||||||
import { GlobalState, GlobalActions, ActionTypes } from '../../global/types';
|
import { GlobalState, GlobalActions, ActionTypes } from '../../global/types';
|
||||||
import { handleError } from '../../util/handleError';
|
import { handleError } from '../../util/handleError';
|
||||||
|
import { isHeavyAnimating } from '../../hooks/useHeavyAnimationCheck';
|
||||||
|
|
||||||
export default React;
|
export default React;
|
||||||
|
|
||||||
@ -40,12 +41,17 @@ const containers = new Map<string, {
|
|||||||
DEBUG_componentName: string;
|
DEBUG_componentName: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const runCallbacksThrottled = throttleWithRaf(runCallbacks);
|
||||||
|
|
||||||
function runCallbacks() {
|
function runCallbacks() {
|
||||||
|
if (isHeavyAnimating()) {
|
||||||
|
runCallbacksThrottled();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
callbacks.forEach((cb) => cb(currentGlobal));
|
callbacks.forEach((cb) => cb(currentGlobal));
|
||||||
}
|
}
|
||||||
|
|
||||||
const runCallbacksThrottled = throttleWithRaf(runCallbacks);
|
|
||||||
|
|
||||||
// `noThrottle = true` is used as a workaround for iOS gesture history navigation
|
// `noThrottle = true` is used as a workaround for iOS gesture history navigation
|
||||||
export function setGlobal(newGlobal?: GlobalState, noThrottle = false) {
|
export function setGlobal(newGlobal?: GlobalState, noThrottle = false) {
|
||||||
if (typeof newGlobal === 'object' && newGlobal !== currentGlobal) {
|
if (typeof newGlobal === 'object' && newGlobal !== currentGlobal) {
|
||||||
|
|||||||
@ -104,11 +104,11 @@ export function throttleWith<F extends AnyToVoidFunction>(schedulerFn: Scheduler
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function onIdle(cb: NoneToVoidFunction) {
|
export function onIdle(cb: NoneToVoidFunction, timeout?: number) {
|
||||||
// eslint-disable-next-line no-restricted-globals
|
// eslint-disable-next-line no-restricted-globals
|
||||||
if (self.requestIdleCallback) {
|
if (self.requestIdleCallback) {
|
||||||
// eslint-disable-next-line no-restricted-globals
|
// eslint-disable-next-line no-restricted-globals
|
||||||
self.requestIdleCallback(cb);
|
self.requestIdleCallback(cb, { timeout });
|
||||||
} else {
|
} else {
|
||||||
onTickEnd(cb);
|
onTickEnd(cb);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user