While building apps with ElectronJS, most web developers don’t have to learn too many new concepts. The only thing that is completely new is Inter-process Communication (IPC). From reading previous articles, you already know that two processes are running in an Electron app. One is the renderer process, which is an instance of a Chromium browser with which users will interact. The other is the main process, which is somewhat similar to the backend of a typical web-based application. The IPC is responsible for establishing a connection between both of these processes.
1. Asynchronous connections: If you know asynchronous programming then you know what this is. In an asynchronous connection, sending a message will not stop other processes. This means users can still interact with the window. For example, the user presses a button on the renderer window which instructs the main process to fetch something from the database. This process takes time, and we do not want to block the renderer process while data is being loaded. So here, we will send an asynchronous message so that the user can still interact with the window while the data is being fetched from the database.
2. Synchronous connections: If you send a synchronous message, it will stop the browser window, which will resume only when the message is successfully sent. For example, if you want the main process to show a dialog box then this is what you will use so that the user focuses on the dialog box message before continuing their work.
To set up the project, clone this dummy Electron project which has basic Electron code https://github.com/thrive-articles/electron-dummy-project. If you have any trouble understanding this code then you can refer to my basics of ElectronJS article here.
Let’s first send a message from the renderer process to the main process. To do that, add a button to index.html that will trigger our message.
Add the following inside of the body section of our index.html file.
1 2 3 4 5
<h1>Hello World!</h1> < button id = "sendAsync" > Send async message < /button> < script > require('./index.js'); </script>
Also, create a file named index.js that we have required in the HTML file.
Now, add the IPC module in the index.js file.
1 2
const electron = require('electron'); const ipc = electron.ipcRenderer;
The IPC module for the renderer file is called ipcRenderer.
Now we will add an event listener to our button and a function that will execute when we click the button.
1 2 3 4
const asyncButton = document.querySelector('#sendAsync'); asyncButton.addEventListener('click', () => { ipc.send('async-message-incoming', 'Async hi from renderer process'); });
When we click our button it sends a message. The first argument in the ipc.send()
function is a unique message-id which we will use to access this message in the main process and the second parameter is the message.
Now, import the IPC module into the main file. We will show this message as an error dialog box, so import the error dialog module as well.
1 2 3 4
const ipc = require('electron') .ipcMain; const dialog = require('electron') .dialog;
Now to listen for the message we will use the message-id we provided to the message. And while listening to the message we also provide a callback that executes when the message is received. Add the following to the main.js file. It will show a dialog box with the title ‘An error message’ and the body will be the message.
1 2 3
IPC.on('async-message-incoming', (event, message) => { dialog.showErrorBox('An error message', message); });
Now run the command npm run watch.
You should see a window like this. Now click the button.
Our message was conveyed perfectly. But is it really asynchronous? Let’s check. In the index.js modify the event listener like this.
1 2 3 4 5
asyncButton.addEventListener('click', () => { console.log('1'); ipc.send('async-message-incoming', 'Async hi from renderer process'); console.log('2'); });
Modify the message receiving code in main.js like this.
1
2
3
4
5
ipc.on('async-message-incoming', (event, message) => {
setTimeout(() => {
dialog.showErrorBox('An error message', message);
}, 1000);
});
If it is asynchronous and does not stop the app’s life cycle then both the digits 1 should be printed first, then instead of waiting for the dialog box, the digit 2 should appear in the console next. After a second the dialog box will appear.
Open the console in your app using ctrl+shift+i
and then hit the button.
If you run this, you will see that it is indeed asynchronous. First the numbers appear in the console and after a second the dialog box appears.
Now you can remove the setTimeOut function we just put up.
Let’s send back a reply. Modify the message receiving code like this.
1 2 3 4
ipc.on('async-message-incoming', (event, message) => { dialog.showErrorBox('An error message', message); event.sender.send('async-reply', 'Async hi from main.js') });
Add the following code to index.js, it will receive the reply.
1 2 3
ipc.on('async-reply', (event, msg) => { console.log(msg); });
When you run it, you will see that as soon as you close the dialog box a reply pops up in the console.
Now let’s add another button in the HTML file that we will use to send synchronous messages.
<button id="sendSync">Send sync message</button>
Add the following code to index.js
1 2 3 4 5
const syncButton = document.querySelector('#sendSync'); syncButton.addEventListener('click', () => { const reply = ipc.sendSync('sync-message-incoming', 'Sync hi from renderer process'); console.log(reply); });
We use the sendSync()
function to send a synchronous message and the reply is returned from this function itself.
Add the following code to main.js
1 2 3
ipc.on('sync-message-incoming', (event) => { event.returnValue = 'Sync hi from main.js' });
Now open the console in the app and send the synchronous message using the second button. You will see the reply in the console.
Thanks for reading about IPC communication. Hope you liked it. Happy coding ✌