[Perf] Fix global updates with interval when in background (#2707)

This commit is contained in:
Alexander Zinchuk 2023-03-03 14:30:56 +01:00
parent 2cde76ea94
commit e480499a80
4 changed files with 36 additions and 74 deletions

View File

@ -50,7 +50,7 @@ const App: FC<StateProps> = ({
hasWebAuthTokenFailed,
isInactiveAuth,
}) => {
const { disconnect, updatePageTitle } = getActions();
const { disconnect } = getActions();
const [isInactive, markInactive, unmarkInactive] = useFlag(false);
const { isMobile } = useAppLayout();
@ -157,7 +157,7 @@ const App: FC<StateProps> = ({
markInactive();
});
}, [activeKey, disconnect, markInactive, updatePageTitle]);
}, [activeKey, disconnect, markInactive]);
useEffect(() => {
if (isInactiveAuth) {
@ -166,7 +166,7 @@ const App: FC<StateProps> = ({
} else {
unmarkInactive();
}
}, [isInactiveAuth, markInactive, unmarkInactive, updatePageTitle]);
}, [isInactiveAuth, markInactive, unmarkInactive]);
const prevActiveKey = usePrevious(activeKey);

View File

@ -1,11 +1,10 @@
import { addCallback } from '../../../lib/teact/teactn';
import {
addActionHandler, getActions, getGlobal, setGlobal,
addActionHandler, getGlobal, setGlobal,
} from '../../index';
import type { ApiError, ApiNotification } from '../../../api/types';
import { MAIN_THREAD_ID } from '../../../api/types';
import type { ActionReturnType, GlobalState } from '../../types';
import type { ActionReturnType } from '../../types';
import {
APP_VERSION, DEBUG, GLOBAL_STATE_CACHE_CUSTOM_EMOJI_LIMIT, INACTIVE_MARKER, PAGE_TITLE,
@ -19,7 +18,7 @@ import { compact, unique } from '../../../util/iteratees';
import { getAllMultitabTokens, getCurrentTabId, reestablishMasterToSelf } from '../../../util/establishMultitabRole';
import { getAllNotificationsCount } from '../../../util/folderManager';
import updateIcon from '../../../util/updateIcon';
import setPageTitle from '../../../util/updatePageTitle';
import { setPageTitle, setPageTitleInstant } from '../../../util/updatePageTitle';
import { updateTabState } from '../../reducers/tabs';
import { getIsMobile, getIsTablet } from '../../../hooks/useAppLayout';
import * as langProvider from '../../../util/langProvider';
@ -606,47 +605,34 @@ addActionHandler('afterHangUp', (global): ActionReturnType => {
let notificationInterval: NodeJS.Timeout | undefined;
const NOTIFICATION_INTERVAL = 1000;
const NOTIFICATION_INTERVAL = 500;
addActionHandler('onTabFocusChange', (global, actions, payload): ActionReturnType => {
const { isBlurred } = payload;
const token = getCurrentTabId();
const { isBlurred, tabId = getCurrentTabId() } = payload;
if (!isBlurred) {
actions.updateIsOnline(true);
}
const blurredTabTokens = unique(isBlurred
? [...global.blurredTabTokens, token]
: global.blurredTabTokens.filter((t) => t !== token));
? [...global.blurredTabTokens, tabId]
: global.blurredTabTokens.filter((t) => t !== tabId));
if (blurredTabTokens.length === getAllMultitabTokens().length) {
actions.updateIsOnline(false);
}
const isNewlyBlurred = isBlurred && blurredTabTokens.length === 1;
if (isNewlyBlurred) {
if (isBlurred) {
if (notificationInterval) clearInterval(notificationInterval);
notificationInterval = setInterval(() => {
global = getGlobal();
global = {
...global,
notificationIndex: (global.notificationIndex || 0) + 1,
allNotificationsCount: getAllNotificationsCount(),
};
setGlobal(global);
actions.updatePageTitle({
tabId,
});
}, NOTIFICATION_INTERVAL);
}
if (!blurredTabTokens.length && notificationInterval) {
} else {
clearInterval(notificationInterval);
notificationInterval = undefined;
global = {
...global,
notificationIndex: undefined,
};
}
return {
@ -657,20 +643,30 @@ addActionHandler('onTabFocusChange', (global, actions, payload): ActionReturnTyp
});
addActionHandler('updatePageTitle', (global, actions, payload): ActionReturnType => {
const { isInactive, notificationCount, tabId = getCurrentTabId() } = payload || {};
const { tabId = getCurrentTabId() } = payload || {};
const { canDisplayChatInTitle } = global.settings.byKey;
const currentUserId = global.currentUserId;
if (isInactive) {
setPageTitle(`${PAGE_TITLE} ${INACTIVE_MARKER}`);
if (document.title.includes(INACTIVE_MARKER)) {
updateIcon(false);
setPageTitleInstant(`${PAGE_TITLE} ${INACTIVE_MARKER}`);
return;
}
if (notificationCount) {
setPageTitle(`${notificationCount} notification${notificationCount > 1 ? 's' : ''}`);
return;
if (global.initialUnreadNotifications && Math.round(Date.now() / 1000) % 2 === 0) {
const notificationCount = getAllNotificationsCount();
const newUnread = notificationCount - global.initialUnreadNotifications;
if (newUnread > 0) {
setPageTitleInstant(`${newUnread} notification${newUnread > 1 ? 's' : ''}`);
updateIcon(true);
return;
}
}
updateIcon(false);
const messageList = selectCurrentMessageList(global, tabId);
if (messageList && canDisplayChatInTitle) {
const { chatId, threadId } = messageList;
@ -687,34 +683,5 @@ addActionHandler('updatePageTitle', (global, actions, payload): ActionReturnType
}
}
setPageTitle(PAGE_TITLE);
});
addCallback((global: GlobalState) => {
if (global.notificationIndex === undefined || global.allNotificationsCount === undefined) return;
// eslint-disable-next-line eslint-multitab-tt/no-getactions-in-actions
const { updatePageTitle } = getActions();
const index = global.notificationIndex;
const allNotificationsCount = global.allNotificationsCount;
if (document.title.includes(INACTIVE_MARKER) || !global.initialUnreadNotifications) {
updateIcon(false);
updatePageTitle();
return;
}
if (index % 2 === 0) {
const newUnread = allNotificationsCount - global.initialUnreadNotifications;
if (newUnread > 0) {
updatePageTitle({
notificationCount: newUnread,
});
updateIcon(true);
return;
}
}
updatePageTitle();
updateIcon(false);
setPageTitleInstant(PAGE_TITLE);
});

View File

@ -560,8 +560,6 @@ export type GlobalState = {
leftColumnWidth?: number;
lastIsChatInfoShown?: boolean;
initialUnreadNotifications?: number;
notificationIndex?: number;
allNotificationsCount?: number;
audioPlayer: {
lastPlaybackRate: number;
@ -1533,7 +1531,7 @@ export interface ActionPayloads {
};
onTabFocusChange: {
isBlurred: boolean;
};
} & WithTabId;
onSomeTabSwitchedMultitabRole: undefined;
afterHangUp: undefined;
requestMasterAndCallAction: CallbackAction & WithTabId;
@ -2169,10 +2167,7 @@ export interface ActionPayloads {
} & WithTabId;
dismissNotification: { localId: string } & WithTabId;
updatePageTitle: {
isInactive?: boolean;
notificationCount?: number;
} & WithTabId | undefined;
updatePageTitle: WithTabId | undefined;
// Calls
joinGroupCall: {

View File

@ -4,11 +4,11 @@ const UPDATE_DEBOUNCE_MS = 200;
// For some reason setting `document.title` to the same value
// causes increment of Chrome Dev Tools > Performance Monitor > DOM Nodes counter
function updatePageTitle(nextTitle: string) {
export function setPageTitleInstant(nextTitle: string) {
if (document.title !== nextTitle) {
document.title = nextTitle;
}
}
// Synchronous page title update has conflicts with History API in Chrome
export default debounce(updatePageTitle, UPDATE_DEBOUNCE_MS, false);
export const setPageTitle = debounce(setPageTitleInstant, UPDATE_DEBOUNCE_MS, false);