Getting Started with Electron: Building Desktop Apps for Web Developers

Advanced Inter-Process Communication Patterns

Section 3

Chapter 7: Advanced Topics and Best Practices

Getting Started with Electron: Building Desktop Apps for Web DevelopersChapter 7: Advanced Topics and Best Practices

Electron applications, by their very nature, are built on a multi-process architecture. The main process is responsible for native OS interactions, while renderer processes (typically one per browser window) handle your web content. This separation, while powerful, necessitates Inter-Process Communication (IPC) to enable these processes to talk to each other. In Chapter 4, we introduced the basics of IPC using ipcRenderer.send and ipcMain.on. Now, let's dive into more advanced patterns that can lead to more robust, maintainable, and efficient applications.

The default ipcRenderer.send and ipcMain.on mechanism is asynchronous. This means that when a renderer process sends a message, it doesn't wait for a response. The main process handles the message and can respond later. However, there are scenarios where the renderer process needs a specific result back from the main process. For these cases, Electron provides ipcRenderer.invoke and ipcMain.handle.

This pattern is crucial for operations that might take some time, like reading a file or making a network request. Using invoke and handle ensures that the renderer process waits for the result without blocking the UI thread. The handle function in the main process must return a Promise or a value, which will be resolved by invoke in the renderer process.

/* renderer.js */
async function readFileContent(filePath) {
  try {
    const content = await ipcRenderer.invoke('read-file', filePath);
    console.log('File content:', content);
  } catch (error) {
    console.error('Error reading file:', error);
  }
}
/* main.js */
const { app, BrowserWindow, ipcMain } = require('electron');
const fs = require('fs');

ipcMain.handle('read-file', async (event, filePath) => {
  try {
    const content = await fs.promises.readFile(filePath, 'utf-8');
    return content;
  } catch (error) {
    throw new Error(`Failed to read file: ${error.message}`);
  }
});

While asynchronous communication is generally preferred, there are rare occasions where you might need a synchronous response. For instance, retrieving a setting that the application absolutely needs before it can proceed, and where a delay would be catastrophic. Electron provides ipcRenderer.sendSync and ipcMain.on with a returnValue property.

チャプターへ戻る