Electron 主进程和渲染进程通信

每个 Electron 应用都有一个单一的主进程,BrowserWindow 类的每个实例创建一个应用程序窗口,且在单独的渲染器进程中加载一个网页。本章我们来介绍下,如何在主进程和渲染器进程之间传递消息

渲染器向主进程发送消息

invoke / handle

渲染进程通过 invoke 向主进程发起异步调用,主进程通过 handle 处理并返回 promise

Electron 的 IPC 通信底层基于「通道名 - 数据」的映射机制,通道名是唯一标识通信逻辑的键

javascript 复制代码
ipcRenderer.invoke("renderer-invoke", message)
javascript 复制代码
const { app, BrowserWindow, ipcMain } = require('electron');
const path = require('node:path');
let window;
app.on('ready', () => {
    window = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
            preload: path.join(__dirname, 'preload.js')
        }
    });
    window.loadFile('index.html');
});

ipcMain.handle("renderer-invoke", (event, message) => {
  console.log("main receive from renderer: ", message);
  return "hello world"
});

我们定义了一个 "renderer-invoke" 通道名,渲染进程通过这个通道名给主进程发送消息,主进程输出消息,并返回 "hello world"。

我们将 ipcRenderer.invoke 通过预加载脚本暴露给渲染进程。

javascript 复制代码
const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('messageApi', {
    send :(message) => ipcRenderer.invoke("renderer-invoke", message)
});

渲染进程调用发送消息接口

javascript 复制代码
async function send () {
    const textContainer = document.getElementById('text-container');
    const result = await window.messageApi.send("hello");
    textContainer.textContent = result;
}
send()

html 显示

html 复制代码
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>消息通信示例</title>
</head>
<body>
    <h1>Hello Electron!</h1>
    <div id="text-container"></div>
    <script src="./renderer.js"> </script>
</body>
</html>

npm start 运行,我们可以看到终端输出了,main receive from renderer: hello,界面上显示主进程返回的字符串 hello world。

send / on

send / on 用于单向通信,这里的单向指的是渲染进程不能通过像 invoke 那样获取主进程返回的结果,但是我们仍可以通过 event.reply 将结果发送给渲染进程。

同样的,我们调用 ipcRenderer.send 接口发送消息,使用预处理脚本暴露接口。

javascript 复制代码
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('messageApi', {
    sendMessage: (message) => ipcRenderer.send("renderer-main", message),
    onReceiveMessage: (callback) => {
        ipcRenderer.on("main-renderer", (_event, message) => {
            callback(message);
        });
    }
});

ipcRenderer.on 用于接收主进程的返回值,后面,渲染进程接收主进程发送的消息也是用同样的接口。

javascript 复制代码
const { app, BrowserWindow, ipcMain } = require('electron');
const path = require('node:path');
let window;
app.on('ready', () => {
    window = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
            preload: path.join(__dirname, 'preload.js')
        }
    });
    window.loadFile('index.html');
ipcMain.on("renderer-main", (event, message) => {
  console.log("main receive from renderer", message);
  event.reply("main-renderer", "received");
});

主进程接收消息,并返回 received,其实从这里可以看出,send / on 的返回更像是主进程收到消息后,主动又发了一个新的消息。

javascript 复制代码
window.messageApi.onReceiveMessage((message) => {
    const textContainer = document.getElementById('text-container');
    textContainer.textContent = message;
});
window.messageApi.sendMessage("hello");

renderer 进程注册回调函数处理收到的消息,然后发送消息。

sendSync / on

ipcRenderer.sendSync API 向主进程发送消息,并同步 等待响应。它会阻塞渲染进程,直至主进程返回

预加载脚本暴露接口

javascript 复制代码
const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('messageApi', {
    syncSendMessage: (message) => ipcRenderer.sendSync("synchronous-message", message)
});

主进程回调处理

javascript 复制代码
const { app, BrowserWindow, ipcMain } = require('electron');
const path = require('node:path');
let window;
app.on('ready', () => {
    window = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
            preload: path.join(__dirname, 'preload.js')
        }
    });
    window.loadFile('index.html');
});

ipcMain.on("synchronous-message", (event, message) => {
  console.log("main receive from renderer", message);
  event.returnValue = "synchronous";
});

渲染进程发送消息,显示结果

javascript 复制代码
const textContainer = document.getElementById('text-container');
const result = window.messageApi.syncSendMessage("hello")
textContainer.textContent = result;

主进程向渲染进程发送消息

主进程可以通过 webContents.send api 主动向渲染进程发送消息

javascript 复制代码
const { app, BrowserWindow, ipcMain } = require('electron');
const path = require('node:path');
let window;
app.on('ready', () => {
    window = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
            preload: path.join(__dirname, 'preload.js')
        }
    });
    window.loadFile('index.html');
    
    window.webContents.on('did-finish-load', () => {
        window.webContents.send("main-renderer", "hello");
    });
});

由于渲染进程可以有多个,所以不是像 ipcRenderer.send 那样发送,而是通过 BrowserWindow 的 webContents.send 发送消息,其他部分和渲染进程向主进程发送消息几乎一致。

javascript 复制代码
const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('messageApi', {
    onReceiveMessage: (callback) => {
        ipcRenderer.on("main-renderer", (_event, message) => {
            callback(message);
        });
    }
});

预加载脚本暴露接口

cpp 复制代码
window.messageApi.onReceiveMessage((message) => {
    const textContainer = document.getElementById('text-container');
    textContainer.textContent = message;
});

渲染进程接收消息

渲染进程向渲染进程发送消息

ipcMain 和 ipcRenderer 模块无法在渲染进程之间发送消息,我们可以通过主进程进行中转,又或者通过 MessageChannelMain 模块来实现,这部分我们在之后的章节再详细介绍。

相关推荐
一 乐8 小时前
婚纱摄影网站|基于ssm + vue婚纱摄影网站系统(源码+数据库+文档)
前端·javascript·数据库·vue.js·spring boot·后端
xkxnq10 小时前
第二阶段:Vue 组件化开发(第 16天)
前端·javascript·vue.js
Van_Moonlight10 小时前
RN for OpenHarmony 实战 TodoList 项目:空状态占位图
javascript·开源·harmonyos
xkxnq11 小时前
第一阶段:Vue 基础入门(第 15天)
前端·javascript·vue.js
学海无涯,行者无疆11 小时前
把 Web App 装进客户端——Tauri框架实战:托盘功能、消息通知、构建安装程序
electron·tauri·单例运行·web应用客户端化·托盘通知·tauri实战·tauri框架
BBBBBAAAAAi12 小时前
Claude Code安装记录
开发语言·前端·javascript
源码获取_wx:Fegn089512 小时前
基于 vue智慧养老院系统
开发语言·前端·javascript·vue.js·spring boot·后端·课程设计
Jing_Rainbow13 小时前
【 前端三剑客-37 /Lesson61(2025-12-09)】JavaScript 内存机制与执行原理详解🧠
前端·javascript·程序员
UIUV14 小时前
模块化CSS学习笔记:从作用域问题到实战解决方案
前端·javascript·react.js
Kakarotto14 小时前
使用ThreeJS绘制东方明珠塔模型
前端·javascript·vue.js