Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add a callback to ipc renderer send

Tags:

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

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].

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');
like image 604
Sophie McCarrell Avatar asked Jul 17 '17 15:07

Sophie McCarrell


People also ask

What is IPC renderer?

The ipcRenderer module is an EventEmitter. It provides a few methods so you can send synchronous and asynchronous messages from the render process (web page) to the main process. You can also receive replies from the main process.

How do you send data from main process to renderer process?

To send a message back to the renderer you would use: win. webContents. send('asynchronous-message', {'SAVED': 'File Saved'});

How does IPC electron work?

IPC channels​ In Electron, processes communicate by passing messages through developer-defined "channels" with the ipcMain and ipcRenderer modules. These channels are arbitrary (you can name them anything you want) and bidirectional (you can use the same channel name for both modules).


1 Answers

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:

main.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.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.

main.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    
})();
like image 129
Tobey Blaber Avatar answered Sep 22 '22 03:09

Tobey Blaber