fix: delay 500ms for window menu, which won't be use in start, but will require CPU resources. And if not in settimeout, getting service itself from ioc container will cause infinite loop. Causing RangeError: Maximum call stack size exceededException in PromiseRejectCallback

This commit is contained in:
linonetwo 2023-12-31 16:24:14 +08:00
parent 5093da125f
commit 3deaa14b7a
6 changed files with 145 additions and 120 deletions

View file

@ -1 +1,3 @@
export const LOAD_VIEW_MAX_RETRIES = 10;
// delay 500ms for window menu, which won't be use in start, but will require CPU resources. And if not in settimeout, getting service itself from ioc container will cause infinite loop. Causing `RangeError: Maximum call stack size exceededException in PromiseRejectCallback`
export const DELAY_MENU_REGISTER = 500;

View file

@ -27,6 +27,7 @@ import { IpcSafeMenuItem, mainMenuItemProxy } from './contextMenu/rendererMenuIt
import { InsertMenuAfterSubMenuIndexError } from './error';
import type { IMenuService, IOnContextMenuInfo } from './interface';
import { DeferredMenuItemConstructorOptions } from './interface';
import { loadDefaultMenuTemplate } from './loadDefaultMenuTemplate';
@injectable()
export class MenuService implements IMenuService {
@ -69,12 +70,12 @@ export class MenuService implements IMenuService {
@lazyInject(serviceIdentifier.WorkspaceView)
private readonly workspaceViewService!: IWorkspaceViewService;
private _menuTemplate?: DeferredMenuItemConstructorOptions[];
#menuTemplate?: DeferredMenuItemConstructorOptions[];
private get menuTemplate(): DeferredMenuItemConstructorOptions[] {
if (this._menuTemplate === undefined) {
this.loadDefaultMenuTemplate();
if (this.#menuTemplate === undefined) {
this.#menuTemplate = loadDefaultMenuTemplate();
}
return this._menuTemplate!;
return this.#menuTemplate;
}
/**
@ -147,119 +148,6 @@ export class MenuService implements IMenuService {
);
}
/**
* Defer to i18next ready to call this
*/
private loadDefaultMenuTemplate(): void {
this._menuTemplate = [
{
label: () => i18n.t('Menu.TidGi'),
id: 'TidGi',
submenu: [
{
label: () => i18n.t('ContextMenu.About'),
click: async () => {
await this.windowService.open(WindowNames.about);
},
},
{ type: 'separator' },
{
id: 'update',
label: () => i18n.t('Updater.CheckUpdate'),
click: async () => {
await this.updaterService.checkForUpdates();
},
},
{
label: () => i18n.t('ContextMenu.Preferences'),
accelerator: 'CmdOrCtrl+,',
click: async () => {
await this.windowService.open(WindowNames.preferences);
},
},
{ type: 'separator' },
{
label: () => i18n.t('Preference.Notifications'),
click: async () => {
await this.windowService.open(WindowNames.notifications);
},
accelerator: 'CmdOrCtrl+Shift+N',
},
{ type: 'separator' },
{ role: 'services', submenu: [] },
{ type: 'separator' },
{ role: 'hide' },
{ role: 'hideOthers' },
{ role: 'unhide' },
{ label: () => i18n.t('ContextMenu.Quit') + i18n.t('Menu.TidGi'), role: 'quit' },
],
},
{
label: () => i18n.t('Menu.Edit'),
id: 'Edit',
role: 'editMenu',
},
{
label: () => i18n.t('Menu.View'),
id: 'View',
},
{
label: () => i18n.t('Menu.Language'),
id: 'Language',
},
{
label: () => i18n.t('Menu.History'),
id: 'History',
},
{
label: () => i18n.t('Menu.Workspaces'),
id: 'Workspaces',
submenu: [],
},
{
label: () => i18n.t('Menu.Wiki'),
id: 'Wiki',
submenu: [],
},
{
label: () => i18n.t('Menu.Window'),
role: 'windowMenu',
id: 'Window',
},
{
label: () => i18n.t('Menu.Help'),
role: 'help',
id: 'help',
submenu: [
{
label: () => i18n.t('ContextMenu.TidGiSupport'),
click: async () => {
await shell.openExternal('https://github.com/tiddly-gittly/TidGi-desktop/issues');
},
},
{
label: () => i18n.t('Menu.ReportBugViaGithub'),
click: async () => {
await shell.openExternal('https://github.com/tiddly-gittly/TidGi-desktop/issues');
},
},
{
label: () => i18n.t('Menu.RequestFeatureViaGithub'),
click: async () => {
await shell.openExternal('https://github.com/tiddly-gittly/TidGi-desktop/issues/new?template=feature.md&title=feature%3A+');
},
},
{
label: () => i18n.t('Menu.LearnMore'),
click: async () => {
await shell.openExternal('https://github.com/tiddly-gittly/TidGi-desktop/');
},
},
],
},
];
}
constructor() {
// debounce so build menu won't be call very frequently on app launch, where every services are registering menu items
this.buildMenu = debounce(this.buildMenu.bind(this), 50) as () => Promise<void>;

View file

@ -0,0 +1,126 @@
/* eslint-disable @typescript-eslint/no-misused-promises */
/* eslint-disable @typescript-eslint/require-await */
import { container } from '@services/container';
import { i18n } from '@services/libs/i18n';
import serviceIdentifier from '@services/serviceIdentifier';
import { IUpdaterService } from '@services/updater/interface';
import type { IWindowService } from '@services/windows/interface';
import { WindowNames } from '@services/windows/WindowProperties';
import { shell } from 'electron';
import { DeferredMenuItemConstructorOptions } from './interface';
/**
* Defer to i18next ready to call this
*/
export function loadDefaultMenuTemplate(): DeferredMenuItemConstructorOptions[] {
const windowService = container.get<IWindowService>(serviceIdentifier.Window);
const updaterService = container.get<IUpdaterService>(serviceIdentifier.View);
return [
{
label: () => i18n.t('Menu.TidGi'),
id: 'TidGi',
submenu: [
{
label: () => i18n.t('ContextMenu.About'),
click: async () => {
await windowService.open(WindowNames.about);
},
},
{ type: 'separator' },
{
id: 'update',
label: () => i18n.t('Updater.CheckUpdate'),
click: async () => {
await updaterService.checkForUpdates();
},
},
{
label: () => i18n.t('ContextMenu.Preferences'),
accelerator: 'CmdOrCtrl+,',
click: async () => {
await windowService.open(WindowNames.preferences);
},
},
{ type: 'separator' },
{
label: () => i18n.t('Preference.Notifications'),
click: async () => {
await windowService.open(WindowNames.notifications);
},
accelerator: 'CmdOrCtrl+Shift+N',
},
{ type: 'separator' },
{ role: 'services', submenu: [] },
{ type: 'separator' },
{ role: 'hide' },
{ role: 'hideOthers' },
{ role: 'unhide' },
{ label: () => i18n.t('ContextMenu.Quit') + i18n.t('Menu.TidGi'), role: 'quit' },
],
},
{
label: () => i18n.t('Menu.Edit'),
id: 'Edit',
role: 'editMenu',
},
{
label: () => i18n.t('Menu.View'),
id: 'View',
},
{
label: () => i18n.t('Menu.Language'),
id: 'Language',
},
{
label: () => i18n.t('Menu.History'),
id: 'History',
},
{
label: () => i18n.t('Menu.Workspaces'),
id: 'Workspaces',
submenu: [],
},
{
label: () => i18n.t('Menu.Wiki'),
id: 'Wiki',
submenu: [],
},
{
label: () => i18n.t('Menu.Window'),
role: 'windowMenu',
id: 'Window',
},
{
label: () => i18n.t('Menu.Help'),
role: 'help',
id: 'help',
submenu: [
{
label: () => i18n.t('ContextMenu.TidGiSupport'),
click: async () => {
await shell.openExternal('https://github.com/tiddly-gittly/TidGi-desktop/issues');
},
},
{
label: () => i18n.t('Menu.ReportBugViaGithub'),
click: async () => {
await shell.openExternal('https://github.com/tiddly-gittly/TidGi-desktop/issues');
},
},
{
label: () => i18n.t('Menu.RequestFeatureViaGithub'),
click: async () => {
await shell.openExternal('https://github.com/tiddly-gittly/TidGi-desktop/issues/new?template=feature.md&title=feature%3A+');
},
},
{
label: () => i18n.t('Menu.LearnMore'),
click: async () => {
await shell.openExternal('https://github.com/tiddly-gittly/TidGi-desktop/');
},
},
],
},
] satisfies DeferredMenuItemConstructorOptions[];
}

View file

@ -26,6 +26,7 @@ import { handleCreateBasicWindow } from './handleCreateBasicWindow';
import { IWindowOpenConfig, IWindowService } from './interface';
import { registerBrowserViewWindowListeners } from './registerBrowserViewWindowListeners';
import { registerMenu } from './registerMenu';
import { DELAY_MENU_REGISTER } from '@/constants/parameters';
@injectable()
export class Window implements IWindowService {
@ -50,7 +51,9 @@ export class Window implements IWindowService {
private readonly themeService!: IThemeService;
constructor() {
void registerMenu();
setTimeout(() => {
void registerMenu();
}, DELAY_MENU_REGISTER);
}
public async findInPage(text: string, forward?: boolean, windowName: WindowNames = WindowNames.main): Promise<void> {

View file

@ -33,6 +33,7 @@ import { debouncedSetSettingFile } from './debouncedSetSettingFile';
import type { INewWorkspaceConfig, IWorkspace, IWorkspaceMetaData, IWorkspaceService, IWorkspaceWithMetadata } from './interface';
import { registerMenu } from './registerMenu';
import { workspaceSorter } from './utils';
import { DELAY_MENU_REGISTER } from '@/constants/parameters';
@injectable()
export class Workspace implements IWorkspaceService {
@ -68,8 +69,10 @@ export class Workspace implements IWorkspaceService {
constructor() {
this.workspaces = this.getInitWorkspacesForCache();
void registerMenu();
this.workspaces$ = new BehaviorSubject<Record<string, IWorkspaceWithMetadata>>(this.getWorkspacesWithMetadata());
setTimeout(() => {
void registerMenu();
}, DELAY_MENU_REGISTER);
}
private getWorkspacesWithMetadata(): Record<string, IWorkspaceWithMetadata> {

View file

@ -25,6 +25,7 @@ import type { IWindowService } from '@services/windows/interface';
import { WindowNames } from '@services/windows/WindowProperties';
import type { IWorkspace, IWorkspaceService } from '@services/workspaces/interface';
import { DELAY_MENU_REGISTER } from '@/constants/parameters';
import type { IInitializeWorkspaceOptions, IWorkspaceViewService } from './interface';
import { registerMenu } from './registerMenu';
@ -64,7 +65,9 @@ export class WorkspaceView implements IWorkspaceViewService {
private readonly nativeService!: INativeService;
constructor() {
void registerMenu();
setTimeout(() => {
void registerMenu();
}, DELAY_MENU_REGISTER);
}
public async initializeAllWorkspaceView(): Promise<void> {