目录

Electron开发实践二,进程间通信

在 Electron 中,进程间通信(IPC)是构建功能丰富的桌面应用程序的关键部分。由于 Electron 的主进程和渲染器进程具有不同的职责,IPC 成为执行许多常见任务的唯一方法,例如从 UI 调用原生 API 或从原生菜单触发 Web 内容的更改 ​​。Electron 中包含三种主要的 IPC 模式:

渲染器进程到主进程(单向)

实现从渲染器进程单向发送 IPC 消息到主进程。可以使用ipcRenderer.sendAPI 发送消息,然后使用ipcMain.onAPI 接收。这种模式通常用于从 Web 内容调用主进程 API​​。其中ipcRenderer.send需要通过预加载脚本 preload.js 进行调用,如设置窗口标题。

js 复制代码
import { contextBridge, ipcRenderer } from 'electron'

contextBridge.exposeInMainWorld('electronAPI', {
  setTitle: (title) => ipcRenderer.send('set-title', title),
})

预加载脚本通过exposeInMainWorld添加名为electronAPI的对象到 Window 对象中,electronAPI包含一个setTitle方法,该方法使用ipcRenderer向主进程发送一个消息,并且携带了title参数。

js 复制代码
import { app, BrowserWindow, ipcMain } from 'electron'

app.whenReady().then(() => {
  ipcMain.on('set-title', (event, title) => {
    const webContents = event.sender
    const win = BrowserWindow.fromWebContents(webContents)
    win.setTitle(title)
  })
})

ipcMain.on监听来自渲染进程的set-title消息。当这个消息被接收时,执行以下操作:

  • event对象获取发送消息的渲染进程的webContents
  • 使用BrowserWindow.fromWebContents(webContents)找到与该webContents相关联的BrowserWindow实例。
  • 使用win.setTitle(title)方法设置窗口的标题,其中title是从渲染进程传递来的参数。

然后在页面中通过window.electronAPI.setTitle()方法就可以发送消息给主线程修改标题了。

渲染器进程到主进程(双向)

双向 IPC 常用于从渲染器进程代码调用主进程模块并等待结果。通过ipcRenderer.invokeipcMain.handle结合使用来实现。例如,可以从渲染器进程打开一个原生的文件对话框,并返回所选文件的路径。

与上面一样,给 Window 对象添加方法:

js 复制代码
contextBridge.exposeInMainWorld('electronAPI', {
  openFile: () => ipcRenderer.invoke('dialog:openFile'),
})

在主进程中,使用ipcMain.handle监听事件,事件回调函数返回值将会作为一个Promise返回到ipcRender.invoke的调用。

js 复制代码
app.whenReady().then(() => {
  ipcMain.handle('dialog:openFile', async () => {
    const { canceled, filePaths } = await dialog.showOpenDialog({})
    if (!canceled) {
      return filePaths[0]
    }
  })
})

在渲染进程中,通过预加载脚本注入的方法调用,就能够获取到所选文件的路径.

js 复制代码
window.electronAPI.openFile().then((path) => {
  // 获取到路径处理
})

需要注意的是,Electron 的 IPC 实现使用 HTML 标准的结构化克隆算法来序列化进程之间传递的对象,这意味着只有某些类型的对象可以通过 IPC 通道传递。支持的类型如下:

因此,在处理返回不可序列化的数据时,使用ipcRenderer.invokeipcMain.handle可能就不太适合,如处理流(stream)类型的数据,不能通过返回ReadStream对象或回调函数使页面持续接收数据,这个时候可能需要考虑主进程向渲染进程持续发送数据能力。

主进程到渲染器进程

在主进程中,你可以使用webContents.send方法来向特定的渲染器进程发送信息。首先,你需要获取到渲染器进程的webContents对象。这通常在BrowserWindow对象创建后完成。

js 复制代码
import { app, BrowserWindow, ipcMain } from 'electron'

app.on('ready', () => {
  const mainWindow = new BrowserWindow({
    // 窗口配置
  })

  // 加载页面...
  mainWindow.loadURL('file:///path/to/your/index.html')

  // 创建顶部菜单选项
  Menu.setApplicationMenu(
    Menu.buildFromTemplate([
      {
        label: app.name,
        submenu: [
          {
            // 向渲染器进程发送消息
            click: () => mainWindow.webContents.send('message-from-main', 'Hello from Main Process'),
            label: 'SendMessage',
          },
        ],
      },
    ])
  )
})

可以在预加载脚本中使用ipcRenderer来接收主进程发送的消息。

js 复制代码
ipcRenderer.on('message-from-main', (event, message) => {
  console.log(message) // 输出 'Hello from Main Process'
})

如果需要在页面中获取消息,就需要一个传入回调函数。还是给 Window 对象添加方法,这个方法参数传入一个回调函数。

js 复制代码
contextBridge.exposeInMainWorld('electronAPI', {
  onMainMessage: (callback) => ipcRenderer.on('message-from-main', (event, message) => callback(message)),
})

然后在页面中调用:

js 复制代码
window.electronAPI.onMainMessage((message) => {
  // 可以在这里更新页面内容或执行其他操作
})

上面是直接通过BrowserWindow实例化的窗口的webContents对象发送消息的方式,而在处理ipcMain.onipcMain.handle事件时,可以通过事件对象 (event) 来给对应窗口回复消息。如在ipcMain.on事件处理中,通常使用event.sender.sendevent.reply方法发送回复:

js 复制代码
ipcMain.on('did-finish-load', (event) => {
  // event.sender 实际为当前 webContents 对象
  event.sender.send('message-from-main', 'Hello from Main Process')
  // 通过 event.reply 给对应 webContents 发送消息
  event.reply('message-from-main', 'Hello from Main Process')
})

ipcMain.handle事件中,不存在event.reply方法,所以只能用event.sender.send

源码:wenyikun/chat-electron-app: A ChatGPT chat application developed using Electron. (github.com)

本文是转载文章,点击查看原文
如有侵权,请联系 xyy@jishuzhan.net 删除
相关推荐
大莲芒3 小时前
react 15-16-17-18各版本的核心区别、底层原理及演进逻辑的深度解析--react17
前端·react.js·前端框架
木木黄木木5 小时前
html5炫酷3D文字效果项目开发实践
前端·3d·html5
Li_Ning216 小时前
【接口重复请求】axios通过AbortController解决页面切换过快,接口重复请求问题
前端
胡八一7 小时前
Window调试 ios 的 Safari 浏览器
前端·ios·safari
Dontla7 小时前
前端页面鼠标移动监控(鼠标运动、鼠标监控)鼠标节流处理、throttle、限制触发频率(setTimeout、clearInterval)
前端·javascript
再学一点就睡7 小时前
深拷贝与浅拷贝:代码世界里的永恒与瞬间
前端·javascript
CrimsonHu7 小时前
B站首页的 Banner 这么好看,我用原生 JS + 三大框架统统给你复刻一遍!
前端·javascript·css
Enti7c7 小时前
前端表单输入框验证
前端·javascript·jquery
拉不动的猪7 小时前
几种比较实用的指令举例
前端·javascript·面试
麻芝汤圆7 小时前
MapReduce 的广泛应用:从数据处理到智能决策
java·开发语言·前端·hadoop·后端·servlet·mapreduce