深入理解Electron 进程间通信(IPC)

953 阅读2分钟

1. IPC 通道

在 Electron 中,ipcMainipcRenderer 模块允许主进程和渲染进程通过自定义的通道进行消息传递。这些通道是开发者自定义命名的,可以实现双向通信。

主进程(main.js):

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

function createWindow() {
    let win = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
            preload: path.join(__dirname, 'preload.js')
        }
    });

    win.loadFile('index.html');
}

app.whenReady().then(createWindow);

// 监听来自渲染进程的消息
ipcMain.on('channel-name', (event, arg) => {
    console.log(arg);  // 输出传递的消息内容
});

预加载脚本(preload.js):

const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('api', {
    sendMessage: (msg) => ipcRenderer.send('channel-name', msg)
});

渲染进程(renderer.js):

document.getElementById('sendButton').addEventListener('click', () => {
    window.api.sendMessage('Hello from Renderer');
});

2. 理解上下文隔离的进程

在 Electron 中,使用预加载脚本和 contextBridge API 可以安全地在上下文隔离的渲染进程中暴露 Node.js 和 Electron 功能。

预加载脚本(preload.js) 的示例代码如上所示。

3. 模式 1:渲染进程到主进程(单向)

在这种模式下,渲染进程可以发送消息到主进程,但不直接接收回复。

渲染进程(renderer.js):

ipcRenderer.send('channel-for-main', 'This is a one-way message to main');

主进程(main.js):

ipcMain.on('channel-for-main', (event, message) => {
    console.log(message);
});

4. 模式 2:渲染进程到主进程(双向)

使用 invokehandle 实现渲染进程和主进程之间的双向通信。

渲染进程(renderer.js):

async function fetchData() {
    try {
        const result = await ipcRenderer.invoke('query-data', 'requestData');
        console.log(result);
    } catch (e) {
        console.error(e);
    }
}

fetchData();

主进程(main.js):

ipcMain.handle('query-data', async (event, arg) => {
    return `Received request: ${arg}`;
});

5. 模式 3:主进程到渲染进程

向特定的渲染进程发送消息。

主进程(main.js):

let win = new BrowserWindow({/* options */});
win.webContents.send('message-for-renderer', 'Hello, renderer!');

6. 模式 4:渲染进程到渲染进程

通过主进程作为中间者或使用 MessagePort

主进程(main.js):

ipcMain.on('send-to-other-renderer', (event, message) => {
    let windows = BrowserWindow.getAllWindows();
    windows.forEach(win => {
        if (win.webContents !== event.sender) {
            win.webContents.send('from-other-renderer', message);
        }
    });
});

7. 对象序列化

Electron 使用 HTML5 的 Structured Clone Algorithm 进行 IPC 通信时的对象序列化。

主进程(main.js):

ipcMain.on('send-object', (event, obj) => {
    console.log(obj);  // obj 是一个被序列化传递的对象
});

渲染进程(renderer.js):

ipcRenderer.send('send-object', { name: 'Electron', type: 'Framework' });

这个教程覆盖了 Electron 的各种 IPC 模式,提供了代码示例并解释了如何在不同的上下文中使用这些技术。通过这种方式,您可以灵活地实现各种应用程序功能,同时保持代码的安全性和高效性。