Electron - 限制从主进程到渲染进程的消息流

分享于2022年07月17日 angular electron ipcrenderer typescript 问答
【问题标题】:Electron - 限制从主进程到渲染进程的消息流(Electron - throttle flow of messages from main to render process)
【发布时间】:2022-01-15 04:49:27
【问题描述】:

我目前在接收从我的主进程到我的渲染器进程(在 Angular 中)的活动窗口的恒定流时遇到一些问题。我知道接收每秒更新会破坏我的应用程序,所以我试图使用 setTimeout 来限制它。但这仍然行不通。我该如何解决这个问题?

渲染器 - Angular 中的组件

  ipc: IpcRenderer | undefined | null;

  constructor(private electronService: ElectronService) { }

  ngAfterViewInit(): void {
    this.getActiveWindow();
  }

  getActiveWindow() {
    while(this.electronService.isElectronApp) {
      this.ipc = this.electronService.ipcRenderer;
      this.ipc.send('get-active-window');
      this.ipc.on('get-active-window-reply', (_event, reply) => {
        console.log(reply);
      });
    }
  }

ma​​in.js

const activeWindows = require('electron-active-window');

ipcMain.on('get-active-window', (_event, _arg) => {
  let i = 0;
  setTimeout(function () {
    activeWindows().getActiveWindow().then((result) => {
      win.webContents.send("get-active-window-reply", result)
    })
  }, 10000 * i)
});

到目前为止,我已经尝试了以下方法,但这只会显示一次活动窗口。我想跟踪所有的变化:

渲染器 - Angular 中的组件

 ngOnInit(): void {
    this.getActiveWindow();
  }

  getActiveWindow() {
    if(this.electronService.isElectronApp) {
      this.ipc = this.electronService.ipcRenderer;
      this.ipc.send('get-active-window');
      this.ipc.on('get-active-window-reply', (_event, reply) => {
        console.log(reply);
      });
    }
  }

ma​​in.js

ipcMain.on('get-active-window', (_event, _arg) => {
  activeWindows().getActiveWindow().then((result) => {
    win.webContents.send("get-active-window-reply", result)
  });
});

  • 这段代码有很多问题。您有一个 while 循环,它不断发送事件和注册处理程序。响应处理程序只是发送延迟响应。双方在本质上都有些异步。想想你当前的代码会发生什么以及你想要什么,然后尝试从那里重新工作。
  • @Clashsoft 感谢您的回复。我已经更新了我的问题以显示我目前在哪里。第二次尝试似乎只获得一次窗口标题。我想让这个实时。我该如何解决这个问题?

【解决方案1】:

您只收到一次活动窗口,因为您只在 ngOnInit 中请求它们一次。

所以在我看来,您目前有两种选择。

  1. 您每隔几秒就向客户端请求一次信息
  2. 您让 Electron 应用程序通知客户端有关窗口的信息

选项 1:(仅解决方案 afaik)

render.component

import { interval } from 'rxjs';

...

getActiveWindow() {
  if(this.electronService.isElectronApp) {
    this.ipc = this.electronService.ipcRenderer;
    
    this.ipc.on('get-active-window-reply', (_event, reply) => {
      console.log(reply);
    });

    // A request directly to get "instant" feedback
    this.ipc.send('get-active-window');

    // You could also use setInterval but I prefer rxjs more ;)
    // Don't forget to unsubscribe in ngOnDestroy
    interval(2000).subscribe(() => {
      this.ipc.send('get-active-window');
    });
  }
}

此解决方案会产生大量开销,因为您不需要每隔几秒更新活动窗口,因此我 推荐 这个。

选项 2( 推荐 不起作用):

ma​​in.js

// Sends a message every time a BrowserWindow is created
app.on('browser-window-created', (event, window) => {
  this.sendActiveWindows();
});

// Respond to the client request
ipcMain.on('get-active-window', (_event, _arg) => {
   this.sendActiveWindows();
});

// Helper function
sendActiveWindows(){
  activeWindows().getActiveWindow().then((result) => {
    win.webContents.send("get-active-window-reply", result)
  });
}

如果您还需要关闭窗口时的信息,您需要向 BrowserWindow.on('closed',...) (更多 here )添加一个侦听器,然后通知您的客户。

render.component.ts(仅添加 cmets)

getActiveWindow() {
  if(this.electronService.isElectronApp) {
    this.ipc = this.electronService.ipcRenderer;
    // Request the currently active windows, 
    // otherwise this info is missing until new window is created
    this.ipc.send('get-active-window');
    this.ipc.on('get-active-window-reply', (_event, reply) => {
      console.log(reply);
    });
  }
}

此解决方案更合适,因为您的客户只会在窗口数量发生变化时收到通知,所以我 推荐 这个

更新

在聊天中澄清问题后,您不能使用选项 2,因为您想检测操作系统的活动窗口而不是 Electron 应用程序的活动窗口。 由于信息 选项 1 是唯一 有效的解决方案 这里

  • getActiveWindow 应该可能从区间返回 Observable,否则很好的解决方案!
  • 这取决于你 ;) 你也可以将订阅分配给 getActiveWindow 内部的一个变量,在这种情况下就没有必要了。谢谢:)
  • 感谢@Batajus。我已经尝试了选项 2,但它似乎不起作用。我的 main.js pastebin.com/uV2b12Nm ,我的组件代码在这里: pastebin.com/Ae4Bx0Pu
  • 选项 1 有效,但我在控制台中收到错误 (node:22168) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 get-active-window-reply listeners added to [EventEmitter]. Use emitter.setMaxListeners() to increase limit (Use electron --trace-warnings ...` 以显示警告的创建位置)`,所以这可能不是一个好主意.
  • 初始化程序时它会选择新窗口标题,但当我切换到另一个程序时它不会选择它,例如 Telegram。