Published on

Electron 进程通信:主进程和渲染进程的对话

Authors
  • avatar
    Name
    Violet Chen
    Twitter

Electron 的进程通信(IPC)是开发桌面应用的核心,主进程和渲染进程各司其职,IPC 就是它们之间的“电话线”。这篇聊聊 IPC 的实现和优化。

主进程和渲染进程啥区别?

主进程跑 Node.js,负责系统级操作,比如文件读写、窗口管理。渲染进程跑 Chromium,处理 UI 和 DOM 操作。两者不能直接互访,IPC 提供了一个安全通道。

electronipcMainipcRenderer 模块来实现通信。主进程监听事件,渲染进程发送消息,简单又高效。

基础 IPC 实现

假设我们要写个桌面应用,渲染进程点按钮,触发主进程查系统信息(比如 CPU 使用率),然后返回给 UI 显示。

主进程代码

main.js 中设置监听:

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

app.whenReady().then(() => {
  const win = new BrowserWindow({
    webPreferences: {
      contextIsolation: true, // 安全隔离
      preload: `${__dirname}/preload.js`, // 预加载脚本
    },
  })
  win.loadFile('index.html')

  // 监听渲染进程的消息
  ipcMain.handle('get-cpu-usage', async () => {
    const cpu = os.cpus()
    return cpu[0].times // 返回 CPU 时间信息
  })
})

预加载脚本

preload.js 中暴露安全的 API:

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

contextBridge.exposeInMainWorld('api', {
  getCpuUsage: () => ipcRenderer.invoke('get-cpu-usage'),
})

渲染进程代码

在 React(或其他前端框架)里调用:

// renderer.js 或 React 组件
async function fetchCpuUsage() {
  const cpuData = await window.api.getCpuUsage()
  console.log(cpuData) // 渲染到 UI
}

// JSX 示例
;<button onClick={fetchCpuUsage}>CPU</button>

两种 IPC 模式

  1. 异步通信(invoke/handle:像上面例子,适合需要返回值的场景。ipcRenderer.invoke 返回 Promise,方便处理异步操作。

  2. 同步通信(send/on:适合简单通知:

    // 渲染进程
    ipcRenderer.send('show-notification', '任务完成!')
    
    // 主进程
    ipcMain.on('show-notification', (event, message) => {
      new Notification({ title: '提示', body: message }).show()
    })
    

invoke/handle 更现代,推荐优先使用,因为它支持错误处理和异步逻辑。

优化技巧

  1. 安全第一

    • 启用 contextIsolation: true,避免渲染进程直接访问 Node.js API。
    • 用预加载脚本(preload.js)通过 contextBridge 暴露最小化 API,防止 XSS 攻击。
    contextBridge.exposeInMainWorld('api', {
      safeFunction: () => ipcRenderer.invoke('safe-action'),
    })
    
  2. 性能优化

    • 避免频繁 IPC 调用,合并请求。比如,批量获取系统数据:
      // 主进程
      ipcMain.handle('get-system-info', async () => {
        return {
          cpu: os.cpus(),
          memory: os.freemem(),
        }
      })
      
      减少通信次数,降低 10% 的进程间开销(Node.js 性能分析)。
    • 用事件节流处理高频交互:
      // 渲染进程
      import { throttle } from 'lodash'
      const throttledSend = throttle(() => {
        ipcRenderer.send('update-data', data)
      }, 1000)
      
  3. 错误处理

    • handle 中捕获异常:
      ipcMain.handle('fetch-data', async () => {
        try {
          return await complexOperation()
        } catch (error) {
          throw new Error(`操作失败: ${error.message}`)
        }
      })
      
    • 渲染进程检查错误:
      try {
        const data = await window.api.getData()
      } catch (error) {
        console.error('IPC 错误:', error)
      }
      

调试技巧

  • 用 Electron 的 --inspect 调试主进程:
    electron --inspect=5858 .
    
    在 Chrome 打开 chrome://inspect 连接调试。
  • 检查 IPC 消息用 electron-log
    const log = require('electron-log')
    ipcMain.on('log-event', (event, msg) => log.info(msg))
    

总结

Electron 的 IPC 让主进程和渲染进程配合得像好搭档,异步 invoke/handle 适合复杂交互,send/on 适合简单通知。安全配置和性能优化是关键,特别是 contextIsolation 和批量通信。