Процесс рендеринга Electron: когда мне следует очищать прослушиватели IPC

#javascript #typescript #browser #electron #ipc

#javascript #typescript #браузер #electron #ipc

Вопрос:

У меня есть приложение Electron с включенным в процесс рендеринга ReactJS и вспомогательной инфраструктурой, которая подключается и синхронизирует все хранилища во всех открытых процессах приложения (один основной процесс и несколько процессов рендеринга)

Связь Redux sync реализована через IPCS electron, поэтому у меня есть пара прослушивателей для разных каналов, эти прослушиватели добавляются для каждого процесса рендеринга (окно браузера)

в качестве примера, вот код, который прослушивает отправленные действия из основного процесса:

 export const listenToFromMainDispatchedActions = (store: Store, senderId: string): () => void => {
  const listener = (event: IpcRendererEvent, args: any): void => {
    if (!isValidAppAction(args)) {
      appLogger.warn('Received an invalid action form main!!!');
    } else {
      const action: IAppReduxAction<any> = {
        ...args,
        meta: {
          ...args.meta,
          handler: ReduxActionHandler.RECEIVER,
        },
      };
      if (action.meta.senderId !== senderId) store.dispatch(action);
    }
  };

  ipcRenderer.on(IPCChannels.ACTION_DISPATCH, listener);
  appLogger.warn('STORE_DISPATCH', 'ADDED ACTION_DISPATCH');
  return (): void => {
    ipcRenderer.removeListener(IPCChannels.ACTION_DISPATCH, listener);
    appLogger.warn('STORE_DISPATCH', 'REMOVED ACTION_DISPATCH');
  };
};
  

этот фрагмент кода выполняется в моем index.tsx файле следующим образом:

 // index.tsx
// ...
export const GLOBAL_SENDER_ID = uuidV4();
const store = storeCreator({
  level: 'renderer',
  reducer: renderersReducer,
  sagas: mainAppWindowSagas,
  senderId: GLOBAL_SENDER_ID,
});

const listenerRemover = listenToFromMainDispatchedActions(store, GLOBAL_SENDER_ID);
...
  

Мой вопрос в том, как и когда лучше всего вызвать listenerRemover() , чтобы удалить прослушиватель IPC?

Я пытался перехватить различные события документа / окна, такие как beforeunload и подобные, но безрезультатно. Чтобы все было «гладко», я на самом деле открываю необходимые окна при запуске приложения и скрываю их, закрытие windows скрывает их вместо того, чтобы убивать их, я понимаю, что это проблематично с точки зрения событий, но мне нужен способ изящно удалить эти прослушиватели, я не нашел ничего полезного в документах

Заранее спасибо

Ответ №1:

Итак, решение, которое я придумал, заключается в следующем:

на стороне браузера / процесс рендеринга (в index.tsx ) я делаю следующее:

 // index.tsx (renderer process)
// ...
export const GLOBAL_SENDER_ID = uuidV4();
const store = storeCreator({
  level: 'renderer',
  reducer: renderersReducer,
  sagas: mainAppWindowSagas,
  senderId: GLOBAL_SENDER_ID,
});

const listenerRemover = listenToFromMainDispatchedActions(store, GLOBAL_SENDER_ID);

const cleanup = (): void => {
   appLogger.log('WINDOW CLOSING');
   listenerRemover();
   window.removeEventListener('beforeunload', cleanup);
}

window.addEventListener('beforeunload', cleanup)
...
  

и в основном процессе я удаляю все аналоги ipcMain:

 // index.ts
import { app, ipcMain } from 'electron';
import main from './main'
// ....
app.whenReady()
  .then(main)
  .catch((error) => {
    appLogger.error(TAG, error);
  });

// .....
app.on('before-quit', () => {
  Object.values(IPCChannels).forEach(
    (channel) => {
      ipcMain.removeAllListeners(channel);
    }
  );
  appLogger.log('CLEANED ALL IPCS');
  appLogger.log('Done, BYEBYE');
});


  

Кажется, он работает так, как ожидалось, и мне удается просмотреть журналы в соответствующих местах, хотя я не совсем уверен в правильности этого подхода, я оставлю свой вопрос без ответа на пару дней (сегодня 13.08.2020 12: 15 по восточному времени).

Если я не получу никаких других / лучших ответов через неделю или около того, я приму свой ответ как правильный.

Комментарии:

1. Принял мой собственный ответ, поскольку не было других более эффективных решений, сегодня 21.08.2020 15: 53 CEST