From f13b1950ef662e964eecd3e470d16e2982174ad0 Mon Sep 17 00:00:00 2001 From: Alexander Zinchuk Date: Wed, 4 Aug 2021 02:35:22 +0300 Subject: [PATCH] [Perf] Do not save cache during heavy animation --- src/components/main/Main.tsx | 64 +++++++++++++++++++++-------- src/components/ui/Transition.tsx | 20 ++++----- src/global/cache.ts | 17 +++++++- src/hooks/useHeavyAnimationCheck.ts | 4 +- 4 files changed, 73 insertions(+), 32 deletions(-) diff --git a/src/components/main/Main.tsx b/src/components/main/Main.tsx index 8ca0bf9ee..17be5446f 100644 --- a/src/components/main/Main.tsx +++ b/src/components/main/Main.tsx @@ -5,10 +5,11 @@ import { getGlobal, withGlobal } from '../../lib/teact/teactn'; import { GlobalActions } from '../../global/types'; import { ApiMessage } from '../../api/types'; +import { LangCode } from '../../types'; import '../../modules/actions/all'; import { - ANIMATION_END_DELAY, BASE_EMOJI_KEYWORD_LANG, DEBUG, INACTIVE_MARKER, PAGE_TITLE, + BASE_EMOJI_KEYWORD_LANG, DEBUG, INACTIVE_MARKER, PAGE_TITLE, } from '../../config'; import { pick } from '../../util/iteratees'; import { @@ -20,9 +21,11 @@ import { } from '../../modules/selectors'; import { dispatchHeavyAnimationEvent } from '../../hooks/useHeavyAnimationCheck'; import buildClassName from '../../util/buildClassName'; +import { fastRaf } from '../../util/schedulers'; import useShowTransition from '../../hooks/useShowTransition'; import useBackgroundMode from '../../hooks/useBackgroundMode'; import useBeforeUnload from '../../hooks/useBeforeUnload'; +import useOnChange from '../../hooks/useOnChange'; import LeftColumn from '../left/LeftColumn'; import MiddleColumn from '../middle/MiddleColumn'; @@ -36,7 +39,6 @@ import SafeLinkModal from './SafeLinkModal.async'; import HistoryCalendar from './HistoryCalendar.async'; import './Main.scss'; -import { LangCode } from '../../types'; type StateProps = { animationLevel: number; @@ -59,10 +61,8 @@ type DispatchProps = Pick; -const ANIMATION_DURATION = 350; const NOTIFICATION_INTERVAL = 1000; -let rightColumnAnimationTimeout: number | undefined; let notificationInterval: number | undefined; let DEBUG_isLogged = false; @@ -128,23 +128,53 @@ const Main: FC = ({ shouldSkipHistoryAnimations && 'history-animation-disabled', ); - // Add `body` classes when toggling right column - useEffect(() => { - if (animationLevel > 0) { - document.body.classList.add('animating-right-column'); - dispatchHeavyAnimationEvent(ANIMATION_DURATION + ANIMATION_END_DELAY); + // Dispatch heavy transition event when opening middle column + useOnChange(([prevIsLeftColumnShown]) => { + if (prevIsLeftColumnShown === undefined || animationLevel === 0) { + return; + } - if (rightColumnAnimationTimeout) { - clearTimeout(rightColumnAnimationTimeout); - rightColumnAnimationTimeout = undefined; + const dispatchHeavyAnimationEnd = dispatchHeavyAnimationEvent(); + const middleColumnEl = document.getElementById('MiddleColumn')!; + + middleColumnEl.addEventListener('transitionend', function handleTransitionEnd(e: TransitionEvent) { + if (e.target !== e.currentTarget) { + return; } - rightColumnAnimationTimeout = window.setTimeout(() => { - document.body.classList.remove('animating-right-column'); - rightColumnAnimationTimeout = undefined; - }, ANIMATION_DURATION + ANIMATION_END_DELAY); + middleColumnEl.removeEventListener('transitionend', handleTransitionEnd); + + dispatchHeavyAnimationEnd(); + }); + }, [isLeftColumnShown]); + + // Dispatch heavy transition event and add body class when opening right column + useOnChange(([prevIsRightColumnShown]) => { + if (prevIsRightColumnShown === undefined || animationLevel === 0) { + return; } - }, [animationLevel, isRightColumnShown]); + + const dispatchHeavyAnimationEnd = dispatchHeavyAnimationEvent(); + const rightColumnEl = document.getElementById('RightColumn')!; + + fastRaf(() => { + document.body.classList.add('animating-right-column'); + }); + + rightColumnEl.addEventListener('transitionend', function handleTransitionEnd(e: TransitionEvent) { + if (e.target !== e.currentTarget) { + return; + } + + rightColumnEl.removeEventListener('transitionend', handleTransitionEnd); + + dispatchHeavyAnimationEnd(); + + fastRaf(() => { + document.body.classList.remove('animating-right-column'); + }); + }); + }, [isRightColumnShown]); const handleBlur = useCallback(() => { updateIsOnline(false); diff --git a/src/components/ui/Transition.tsx b/src/components/ui/Transition.tsx index 8e8b91ca5..5419e9ea8 100644 --- a/src/components/ui/Transition.tsx +++ b/src/components/ui/Transition.tsx @@ -173,18 +173,16 @@ const Transition: FC = ({ }); } - function handleAnimationEnd(e: AnimationEvent) { - if (e.target !== e.currentTarget) { - return; - } - - toNode.removeEventListener('animationend', handleAnimationEnd as EventListener); - - onAnimationEnd(); - } - if (animationLevel > 0) { - toNode.addEventListener('animationend', handleAnimationEnd as EventListener); + toNode.addEventListener('animationend', function handleAnimationEnd(e: AnimationEvent) { + if (e.target !== e.currentTarget) { + return; + } + + toNode.removeEventListener('animationend', handleAnimationEnd as EventListener); + + onAnimationEnd(); + } as EventListener); } else { onAnimationEnd(); } diff --git a/src/global/cache.ts b/src/global/cache.ts index 48de27c53..33d6fc8d6 100644 --- a/src/global/cache.ts +++ b/src/global/cache.ts @@ -15,18 +15,22 @@ import { GLOBAL_STATE_CACHE_USER_LIST_LIMIT, } from '../config'; import { IS_SINGLE_COLUMN_LAYOUT } from '../util/environment'; +import { ANIMATION_END_EVENT, ANIMATION_START_EVENT } from '../hooks/useHeavyAnimationCheck'; import { pick } from '../util/iteratees'; -import { INITIAL_STATE } from './initial'; import { selectCurrentMessageList } from '../modules/selectors'; import { hasStoredSession } from '../util/sessions'; +import { INITIAL_STATE } from './initial'; const UPDATE_THROTTLE = 5000; const updateCacheThrottled = throttle(() => onIdle(updateCache), UPDATE_THROTTLE, false); let isCaching = false; +let isHeavyAnimating = false; let unsubscribeFromBeforeUnload: NoneToVoidFunction | undefined; +setupHeavyAnimationListeners(); + export function initCache() { if (GLOBAL_STATE_CACHE_DISABLED) { return; @@ -124,7 +128,7 @@ function readCache(initialState: GlobalState) { } function updateCache() { - if (!isCaching) { + if (!isCaching || isHeavyAnimating) { return; } @@ -258,3 +262,12 @@ function reduceChatFolders(global: GlobalState): GlobalState['chatFolders'] { activeChatFolder: 0, }; } + +function setupHeavyAnimationListeners() { + document.addEventListener(ANIMATION_START_EVENT, () => { + isHeavyAnimating = true; + }); + document.addEventListener(ANIMATION_END_EVENT, () => { + isHeavyAnimating = false; + }); +} diff --git a/src/hooks/useHeavyAnimationCheck.ts b/src/hooks/useHeavyAnimationCheck.ts index 047d3e30d..84075b4b1 100644 --- a/src/hooks/useHeavyAnimationCheck.ts +++ b/src/hooks/useHeavyAnimationCheck.ts @@ -1,7 +1,7 @@ import { useEffect } from '../lib/teact/teact'; -const ANIMATION_START_EVENT = 'tt-event-heavy-animation-start'; -const ANIMATION_END_EVENT = 'tt-event-heavy-animation-end'; +export const ANIMATION_START_EVENT = 'tt-event-heavy-animation-start'; +export const ANIMATION_END_EVENT = 'tt-event-heavy-animation-end'; let timeout: number | undefined; let isAnimating = false;