如何添加回调到ipc渲染器发送

Jas*_*ell 4 electron

谷歌说你可以添加一个回调,但文档只是说"arg1,arg2,arg3"等.

他们也有sendSync,但我不想在我的事件被发送时阻止[我们试图通过浏览器做尽可能多的工作,因为在节点中编写客户端代码,似乎有些愚蠢].

如果创建者有一个sendSync,那么肯定他们有一个带回调的版本,或者更好的承诺.

我希望能够做的一些事情的例子:

//callback
ipcRenderer.send('anaction', '[1, 2, 3]', function() { console.log('done anaction') });
//promise
ipcRenderer.send('anaction', '[1, 2, 3]')
    .then(function() { console.log('done anaction') });

//sync exists, but it blocks. I'm looking for a non-blocking function
ipcRenderer.sendSync('anacount', '[1, 2, 3]')
console.log('done anaction');
Run Code Online (Sandbox Code Playgroud)

Tob*_*ber 54

万一有人在 2020 年仍在寻找这个问题的答案,处理从主线程返回渲染器的更好方法是根本不使用send,而是使用ipcMain.handleand ipcRenderer.invoke,它利用async/await并返回 Promises :

主文件

import { ipcMain } from 'electron';

ipcMain.handle('an-action', async (event, arg) => {
    // do stuff
    await awaitableProcess();
    return "foo";
}
Run Code Online (Sandbox Code Playgroud)

渲染器.js

import { ipcRenderer } from 'electron';

(async () => {
    const result = await ipcRenderer.invoke('an-action', [1, 2, 3]);
    console.log(result); // prints "foo"
})();
Run Code Online (Sandbox Code Playgroud)

ipcMain.handle并且与ipcRenderer.invoke兼容contextBridge,允许您公开 API 以向主线程询问来自渲染器线程的数据,并在它返回后对其进行处理。

主文件

import { ipcMain, BrowserWindow } from 'electron';

ipcMain.handle('an-action', async (event, arg) => {
    // do stuff
    await awaitableProcess();
    return "foo";
}

new BrowserWindow({
    ...
    webPreferences: {
        contextIsolation: true,
        preload: "preload.js" // MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY if you're using webpack
    }
    ...
});
Run Code Online (Sandbox Code Playgroud)

预加载.js

import { ipcRenderer, contextBridge } from 'electron';

// Adds an object 'api' to the global window object:
contextBridge.exposeInMainWorld('api', {
    doAction: async (arg) => {
        return await ipcRenderer.invoke('an-action', arg);
    }
});
Run Code Online (Sandbox Code Playgroud)

渲染器.js

(async () => {
    const response = await window.api.doAction([1,2,3]);
    console.log(response); // we now have the response from the main thread without exposing
                           // ipcRenderer, leaving the app less vulnerable to attack    
})();
Run Code Online (Sandbox Code Playgroud)

  • 希望我 2 小时前就找到了你的解决方案!谢谢! (5认同)
  • 在 doAction 中我想你不需要额外的 async/await (2认同)

Jas*_*ell 10

感谢unseen_damage提供此建议. https://github.com/electron/electron/blob/master/docs/api/ipc-main.md#sending-messages

// In main process.
const {ipcMain} = require('electron')
ipcMain.on('asynchronous-message', (event, arg) => {
    if(arg === 'ping')
        event.sender.send('asynchronous-reply', 'pong');
    else
        event.sender.send('asynchronous-reply', 'unrecognized arg');
})

// In renderer process (web page).
const {ipcRenderer} = require('electron')
function callAgent(args) {
    return new Promise(resolve => {
        ipcRenderer.send('asynchronous-message', args)
        ipcRenderer.on('asynchronous-reply', (event, result) => {
            resolve(result);
        })
    });
}
Run Code Online (Sandbox Code Playgroud)

  • 实际上你在每次调用时都定义了一个新的回调,这不是可能会导致内存泄漏吗? (3认同)
  • 只需使用“ipcRenderer.once()”并切换顺序 - 首先“ipcRenderer.once()”,然后“ipcRenderer.send()”。 (2认同)