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

2022-01-10 00:00:00 electron javascript

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

Googling says you can add a callback to it, but the documentation just says "arg1, arg2, arg3" etc.

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

They also have sendSync, but I'd prefer not to block while my event is being sent [we're trying to do as much work through the browser as possible, because writing client code in node, seems a little daft].

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

If the creators have a sendSync, then surely they have a version with callbacks, or better yet promises.

一些我想做的事情的例子:

Some examples of things i'd like to be able to do:

//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');

推荐答案

如果有人在 2020 年仍在寻找这个问题的答案,处理从主线程回复到渲染器的更好方法是不要使用send,而是使用 ipcMain.handleipcRenderer.invoke,利用async/await并返回Promises:

In case anybody is still looking for an answer to this question in 2020, a better way to handle replying from the main thread back to the renderer is not to use send at all, but rather to use ipcMain.handle and ipcRenderer.invoke, which make use of async/await and return Promises:

ma​​in.js

import { ipcMain } from 'electron';

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

renderer.js

import { ipcRenderer } from 'electron';

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


ipcMain.handleipcRenderer.invokecontextBridge,允许您公开一个 API 以向主线程请求来自渲染器线程的数据,并在它返回后对其进行处理.


ipcMain.handle and ipcRenderer.invoke are compatible with contextBridge, allowing you to expose an API to ask the main thread for data from the renderer thread and do something with it once it comes back.

ma​​in.js

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
    }
    ...
});

preload.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);
    }
});

renderer.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    
})();

相关文章