29

In electron, It is possible to send sync message from IpcRenderer to IpcMain via ipcRenderer.sendSync('synchronous-message', 'ping').

Also possible to send async message from IpcMain to IpcRenderer using window.webContents.send('ping', 'whoooooooh!')

but is there any way to send sync message from IpcMain to IpcRenderer?

GorvGoyl
  • 42,508
  • 29
  • 229
  • 225
  • 1
    I believe you cannot, because you would block the main node thread this way, which runs renderer processes, too. But I guess you can achieve the same in async fashion by replying in your renderer callback with `event.sender.send` and wait that up in main – pergy Dec 01 '17 at 19:46

4 Answers4

23

There is no such functionality of ipcMain *. However, you can achieve almost the same result asynchronously with the following steps:

  • Place your code which you would run only after the synchronous call in an ipcMain callback.
  • Reply to ipc message in renderer process with the result using event.sender.send

A dummy example of sum using this approach looks like the following:

main.js

const {app, BrowserWindow, ipcMain} = require('electron')
const path = require('path')

app.once('ready', () => {
  let win = new BrowserWindow()
  // have to run "sync", that is only after result is ready
  const doJobWithResult = (res) => {
    console.log(res)
  }
  win.webContents.once('dom-ready', () => {
    win.webContents
    .send('sum-request', 23, 98, 3, 61)
    ipcMain.once('sum-reply', (event, sum) => {
      doJobWithResult(sum)
    })
  })
  win.loadURL(path.resolve(__dirname, 'test.html'))
})

renderer.js (referred from test.html)

const {ipcRenderer} = require('electron')

window.onload = () => {
  const add = (a, b) => {
    return a + b
  }
  ipcRenderer.on('sum-request', (event, ...args) => {
    event.sender.send('sum-reply', [...args].reduce(add, 0))
  })
}

* I suppose it's because calling synchronously from main to renderer would block the main nodejs process which does serve renderer processes too after all.

pergy
  • 5,285
  • 1
  • 22
  • 36
  • To avoid the doJobWithResult callback and have things more in sequence, I would suggest this: async function sum(...args) { win.webContents.send('sum-request', ...args); return await = new Promise((resolve) => { ipcMain.once('sum-reply', (event, sum) => { resolve(sum); }) }); } // do something first console.log(sum(23, 98, 3, 61)); // do something next This is the pattern I use to simulate this missing win.webContents.sendSync – Djee May 20 '20 at 17:48
18

The easiest way to access Main Process Objects in renderer process(sync)

// In renderer process (web page).
const { ipcRenderer } = require('electron');
let exec = eval => ipcRenderer.sendSync('synchronous-message', eval);
exec("win.setSize(500,500)");
console.log(exec("win.getBounds()"));
console.log(exec("app.getVersion()"));

// In the Main process.
ipcMain.on('synchronous-message', (event, arg) => {
  event.returnValue = eval(arg);
})

It's the way to send msg from Main process to renderer process.(Official example)

// In renderer process (web page).
ipcRenderer.on('test', (event, arg) => {
    console.log(arg) // 123
})
// In the Main process.(after loaded you can send msg to renderer process)
win.webContents.on('did-finish-load', () => {
    win.webContents.send('test',123);
})
edwin liang
  • 197
  • 1
  • 4
  • 3
    I'd like to note that allowing unsanitized input from the renderer process to be run in the main process is a huge security risk. If you were to load any web page, you could easily end up with remote code execution... – Shape Sep 01 '21 at 10:38
12

I was trying to do the same, and the closest I got, was sending first the message from the IPCRenderer and then return what you want from the IPCMain event received is with this code snippet:

// In renderer process (web page).
const ipcRenderer = require('electron').ipcRenderer;
console.log(ipcRenderer.sendSync('synchronous-message', 'ping')); // prints "pong"

// In the Main process.
ipcMain.on('synchronous-message', function(event, arg) {
  console.log(arg);  // prints "ping"
  event.returnValue = 'pong';
});
Juan Sanchez
  • 543
  • 7
  • 14
-4

Yes it is possible to send send sync message from IpcRenderer to IpcMain

let {ipcRenderer} = require('electron');

ipcRenderer.sendSync('sync', 'Im the message from the renderer');


// Listen for sync message from renderer process
ipcMain.on('sync', (event, arg) => {  
    console.log(arg);   // Print Im the message from the renderer
});

I suggest you to visit this post, Of VJEKOSLAV RATKAJEC, he explains very well the communication between de ipcMain to ipcRenderer and viceversa.

Link: http://electron.rocks/different-ways-to-communicate-between-main-and-renderer-process/

Juan Sanchez
  • 543
  • 7
  • 14