Electron 主进程、渲染进程及进程间的通信

本文介绍了Electron,它是用HTML、CSS、JS构建跨平台桌面应用的开源库。Electron应用包含主进程和渲染进程,二者相互隔离。文中重点阐述了主进程与渲染进程间的通信方式,着重介绍了使用ipcMain和ipcRenderer模块通信,还提及其他通信方式及注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简介

 Electron是由GIthub开发,用HTML、CSS、JS来构建跨平台桌面应用程序的一个开源库。Electron将Chromium和Nodejs合并到同一个运行时环境中,并将其打包为Mac、Windows、Linux系统下的应用。可以将其看作是一个由JS控制的迷你版的Chromium浏览器。

主进程、渲染进程

Electron打包的应用包含两个部分:Electron的环境(node) — 主进程、web渲染环境 — 渲染进程。

Electron中,入口是js文件(通常为package.json里的main脚本),运行此文件的进程即为主进程,在主进程中使用BrowserWindow模块可以创建并管理web页面,也就是应用的GUI。

const {BrowserWindow} = require('electron');
// 创建浏览器窗口
let win = new BrowserWindow({width: 320, height: 572, resizable: true});
// 加载本地的文件
win.loadURL('file://' + __dirname + '/index.html');
// 打开调试窗口
win.webContents.openDevTools();

在主进程创建的每个web页面都运行着自己的进程,即渲染进程,渲染进程各自独立。

主进程和渲染进程之间是相互隔离的,无法直接进行数据通信。

进程间通信

Web页面因为安全限制,不能直接访问原生的GUI资源,Electron也一样,渲染进程如果想要进行原生的GUI操作,必须和主进程通信,请求相应的GUI操作。

Electron提供了集中渲染进程和主进程通信的方式:

  1. 使用ipcMain和ipcRenderer模块;
  2. 直接在渲染进程中使用remote模块;
  3. 主进程向渲染进程发送消息;
  4. 渲染进程之间的通信。

目前项目中用到的通信方式为第一种,此文只详细介绍第一种。

使用ipcMain和ipcRenderer模块

在渲染进程中使用ipcRenderer模块向主进程发送消息,主进程中ipcMain接收消息,进行操作,如需反馈,则通知渲染进程,渲染进程根据接收的内容执行相应的操作:

// 渲染进程
const ipcRenderer = require('electron').ipcRenderer;
// 同步消息使用sendSync方法,在发出瞬间即可接收到响应内容
console.log(ipcRenderer.sendSync('synchronous-message', 'ping')); // prints "pong"

ipcRenderer.on('asynchronous-reply', function(event, arg) {
  console.log(arg); // prints "pong"
});
// 异步消息使用send方法,需要监听异步事件才能得到响应
ipcRenderer.send('asynchronous-message', 'ping');
// 主进程
const ipcMain = require('electron').ipcMain;
ipcMain.on('asynchronous-message', function(event, arg) {
  console.log(arg);  // prints "ping"
  // 回应异步消息
  event.sender.send('asynchronous-reply', 'pong');
});

ipcMain.on('synchronous-message', function(event, arg) {
  console.log(arg);  // prints "ping"
  // 回应同步消息
  event.returnValue = 'pong';
});

⚠️ 切忌用ipc传递大量的数据,会有很大的性能问题,严重会让整个应用卡住。

ipcMain模块 监听消息 相关函数 

/**
* 监听 channel 事件,当新消息到达,通过listener(event, args...)调用listener
* @param {String} channel  
* @param {Function} listener 
*/
ipcMain.on(channel, listener);

/**
* 同上,但只触发一次,触发后自动取消绑定
* @param {String} channel  
* @param {Function} listener 
*/
ipcMain.once(channel, listener);

/**
* 为特定的 channel 从监听队列中删除特定的 listener 监听者
* @param {String} channel  
* @param {Function} listener 
*/
ipcMain.removeListener(channel, listener);

/**
* 删除所有监听者,或特指的 channel 的所有监听者
* @param {String} channel  
* @param {Function} listener 
*/
ipcMain.removeAllListeners([channel]);

ipcRenderer模块 监听消息 相关函数 

/**
* 监听 channel 事件,当新消息到达,通过listener(event, args...)调用listener
* @param {String} channel  
* @param {Function} listener 
*/
ipcRenderer.on(channel, listener);

/**
* 同上,但只触发一次,触发后自动取消绑定
* @param {String} channel  
* @param {Function} listener 
*/
ipcRenderer.once(channel, listener);

/**
* 为特定的 channel 从监听队列中删除特定的 listener 监听者
* @param {String} channel  
* @param {Function} listener 
*/
ipcRenderer.removeListener(channel, listener);

/**
* 删除所有监听者,或特指的 channel 的所有监听者
* @param {String} channel  
* @param {Function} listener 
*/
ipcRenderer.removeAllListeners([channel]);

ipcRenderer模块 发送消息 相关函数 

/**
* 通过 channel 向主进程发送异步消息,也可以发送任意参数.参数会被JSON序列化,之后就不会包含函数或原型链。主进程通过使用 ipcMain 模块来监听 channel,从而处理消息.通过 event.sender.send() 来响应.
* @param {String} channel  
* @param {} [arg] 
*/
ipcRenderer.send(channel[, arg1][, arg2][, ...]);

/**
* 通过 channel 向主进程发送同步消息,也可以发送任意参数.参数会被JSON序列化,之后就不会包含函数或原型链.主进程通过使用 ipcMain 模块来监听 channel,从而处理消息, 通过 event.returnValue 来响应.
* @param {String} channel  
* @param {} [arg] 
*/
// ⚠️发送同步消息将会阻塞整个渲染进程,除非你知道你在做什么,否则就永远不要用它 .
ipcRenderer.sendSync(channel[, arg1][, arg2][, ...]);

/**
* 类似 ipcRenderer.send ,但是它的事件将发往 host page 的 <webview> 元素,而不是主进程.
* @param {String} channel  
* @param {} [arg] 
*/
ipcRenderer.sendToHost(channel[, arg1][, arg2][, ...]);

直接在渲染进程中使用remote模块

remote 模块可以直接获取主进程中的模块。

// 在渲染进程打开提示对话框
const {dialog} = require('electron').remote
dialog.showMessageBox({ opts });

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

this.webviewWindow.webContents.send('ping');

渲染进程间通信

如果数据不需要实时性,只是渲染进程之间数据的共享,那么使用官方建议即可。如果要求实时性,需要配合前几种种方式实现。

// 主进程
// 两个窗口互相获取对方的窗口 id, 并发送给渲染进程
win1.webContents.send('distributeIds',{
    win2Id : win2.id
});
win2.webContents.send('distributeIds',{
    win1Id : win1.id
});

// 渲染进程
// 通过 id 得到窗口
remote.BrowserWindow.fromId(win2Id).webContents.send('someMsg', 'someThing');

参考:我眼中的 Electron    Electron入门之ipcMain,ipcRenderer

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值