云计算百科
云计算领域专业知识百科平台

Electron 进程与 IPC 通信详解:主进程、渲染进程与 Preload

一、前言

在使用 Electron 开发桌面应用时,经常会接触到:

  • Main Process(主进程)
  • Renderer Process(渲染进程)
  • Preload Script(预加载脚本)
  • IPC(Inter-Process Communication,进程间通信)

很多刚开始学习 Electron 的开发者容易把它们理解成普通的前端线程,但实际上 Electron 的核心架构是多进程模型。

例如我们正在开发一个 Electron + Vue 桌面应用:

Electron

├── Main Process
│ │
│ ├── 创建窗口
│ ├── 文件系统
│ ├── SQLite
│ ├── Node.js
│ └── 系统级能力

├── Preload Script
│ │
│ └── 安全暴露 API

└── Renderer Process

├── Vue
├── HTML
├── CSS
└── 页面交互

那么,Vue 页面如果需要访问 SQLite、读取文件或者启动 Python 服务,就不能直接操作,而是需要通过 IPC 与主进程进行通信。

本文就详细介绍 Electron 的进程模型以及 IPC 通信方式。


二、Electron 的进程模型

Electron 主要由以下几个部分组成:

名称作用常用 API
主进程(Main Process) 创建和管理窗口、执行系统级操作、访问 Node.js API app、BrowserWindow、ipcMain、globalShortcut
渲染进程(Renderer Process) 负责页面 UI 渲染和用户交互 DOM、Vue、浏览器 API
预加载脚本(Preload Script) 连接主进程和渲染进程,在安全环境下暴露 API contextBridge、ipcRenderer

需要特别注意:

Preload 是一个脚本,而不是独立的 Electron 进程。

因此,更准确的理解应该是:

┌────────────────────────────────────────────┐
│ Electron Application │
│ │
│ ┌──────────────┐ │
│ │ Main Process │ │
│ │ │ │
│ │ Node.js │ │
│ │ SQLite │ │
│ │ File System │ │
│ └──────┬───────┘ │
│ │ IPC │
│ │ │
│ ┌──────▼────────┐ │
│ │ Preload │ │
│ │ contextBridge │ │
│ └──────┬────────┘ │
│ │ │
│ ┌──────▼──────────────┐ │
│ │ Renderer Process │ │
│ │ │ │
│ │ Vue │ │
│ │ HTML / CSS / DOM │ │
│ └─────────────────────┘ │
└────────────────────────────────────────────┘


三、主进程(Main Process)

主进程是 Electron 应用的核心进程。
通常一个 Electron 应用只有一个主进程。

主进程主要负责:

  • 创建 BrowserWindow
  • 管理应用生命周期
  • 访问 Node.js API
  • 操作文件系统
  • 操作 SQLite
  • 启动和管理 Python 服务
  • 创建系统托盘
  • 注册全局快捷键
  • 处理 IPC
  • 管理应用级状态

例如:

import { app, BrowserWindow } from 'electron'
let mainWindow: BrowserWindow | null = null
function createWindow() {
mainWindow = new BrowserWindow({
width: 1400,
height: 900,
webPreferences: {
preload: '/path/to/preload.js'
}
})
}
app.whenReady().then(() => {
createWindow()
})

主进程可以访问 Node.js:

import fs from 'node:fs'
import path from 'node:path'

因此,类似下面这些操作通常应该放在主进程:

读取文件

SQLite

启动 Python

操作系统 API

创建窗口


四、渲染进程(Renderer Process)

渲染进程主要负责 UI。

如果我们使用:

Electron + Vue 3 + TypeScript

那么 Vue 应用基本就是运行在渲染进程中。

例如:

<script setup lang="ts">
const handleClick = () => {
console.log('点击按钮')
}
</script>
<template>
<button @click="handleClick">
保存文章
</button>
</template>

渲染进程可以使用:

  • Vue
  • HTML
  • CSS
  • DOM
  • window
  • localStorage
  • 浏览器 API

但是在安全配置下,不应该直接使用 Node.js API。
例如不建议在 Vue 页面中直接:

import fs from 'fs'

也不要让页面直接拥有完整的 Node.js 能力。

原因很简单:
如果网页代码可以直接访问 Node.js,那么一旦页面存在 XSS 等安全问题,攻击者可能获得文件系统等更高权限。

因此 Electron 提供了 Preload Script。


五、Preload Script

Preload 可以理解为:

渲染进程与主进程之间的安全桥梁。

Preload 通常运行在页面加载之前,并通过 contextBridge 向 Vue 暴露有限的 API。

例如:

import { contextBridge, ipcRenderer } from 'electron'
contextBridge.exposeInMainWorld('electronAPI', {
getAppInfo: () => {
return ipcRenderer.invoke('app:getInfo')
}
})

这样 Vue 页面就可以使用:

window.electronAPI.getAppInfo()

但是 Vue 并没有直接获得:

ipcRenderer

或者:

fs

这样的底层能力。

整个调用关系:

Vue

│ window.electronAPI.getAppInfo()

Preload

│ ipcRenderer.invoke()

Main Process

│ ipcMain.handle()

执行具体业务


六、什么是 IPC?

IPC 全称:

Inter-Process Communication

也就是:

进程间通信。

因为 Electron 的主进程和渲染进程是不同的进程,所以它们不能像普通 JavaScript 函数一样直接调用。

例如:

Vue

我要读取一个 Markdown 文件

Main Process

fs.readFile()

返回 Markdown 内容

Vue

中间就需要通过 IPC 传递消息。


七、Electron 常见 IPC 通信方式

Electron 中最常见的 IPC 通信方式主要有:

类型渲染进程主进程特点
请求-响应 ipcRenderer.invoke() ipcMain.handle() 推荐
单向消息 ipcRenderer.send() ipcMain.on() 无返回值
主进程主动推送 ipcRenderer.on() webContents.send() 主进程主动通知

八、渲染进程 → 主进程:invoke / handle

这是开发桌面应用时最推荐的一种方式。

例如:

Vue

invoke()

Preload

ipcRenderer.invoke()

Main

ipcMain.handle()

返回结果


8.1 Main Process

import { ipcMain } from 'electron'
ipcMain.handle('app:getInfo', async () => {
return {
name: 'CSDN Auto',
version: '1.0.0'
}
})


8.2 Preload

import { contextBridge, ipcRenderer } from 'electron'
contextBridge.exposeInMainWorld('electronAPI', {
getAppInfo: () => {
return ipcRenderer.invoke('app:getInfo')
}
})


8.3 Vue

const appInfo = await window.electronAPI.getAppInfo()
console.log(appInfo)

最终得到:

{
"name": "CSDN Auto",
"version": "1.0.0"
}

这种方式特别适合:

获取文章
保存文章
删除文章
查询 SQLite
创建任务
获取账号
读取配置

因为它具有明确的:

请求

处理

返回

关系。


九、渲染进程 → 主进程:send / on

如果不需要返回结果,可以使用:

ipcRenderer.send()

配合:

ipcMain.on()

例如:
Preload

contextBridge.exposeInMainWorld('electronAPI', {
writeLog: (message: string) => {
ipcRenderer.send('log:write', message)
}
})

Main

ipcMain.on('log:write', (_event, message) => {
console.log('[Renderer]', message)
})

Vue

window.electronAPI.writeLog('用户点击了发布按钮')

这种方式适合:

日志
埋点
通知
不需要返回值的操作

不过对于大多数业务请求,还是更推荐:

invoke / handle


十、主进程 → 渲染进程

有些时候不是 Vue 主动请求,而是主进程产生了新的状态,需要主动通知 Vue。

例如:

Python 自动发布文章

任务进度发生变化

Electron Main

通知 Vue

进度条更新

这时候可以使用:

webContents.send()

配合:

ipcRenderer.on()


10.1 Main Process

mainWindow.webContents.send(
'task:progress',
{
taskId: 'task_001',
progress: 60
}
)


10.2 Preload

contextBridge.exposeInMainWorld('electronAPI', {
onTaskProgress: (callback) => {
ipcRenderer.on('task:progress', (_event, data) => {
callback(data)
})
}
})


10.3 Vue

window.electronAPI.onTaskProgress((data) => {
console.log('任务进度:', data.progress)
})

页面就可以实时更新:

正在发布文章…
████████████░░░░░░░░ 60%


十一、推荐的 IPC 使用原则

实际开发中,可以按照下面的原则设计。

  • 默认使用 invoke / handle
  • 例如:

    查询文章
    保存文章
    删除文章
    创建任务
    查询账号
    读取配置

    统一:

    ipcRenderer.invoke()

    ipcMain.handle()


  • 主进程主动推送使用 send / on
  • 例如:

    任务进度
    Python 状态
    发布日志
    下载进度
    窗口状态

    使用:

    webContents.send()

    ipcRenderer.on()


  • send / on 只用于真正的单向通知
  • 例如:

    记录日志
    发送统计信息
    通知主进程刷新

    不要所有东西都使用:

    send / on

    否则后期很容易出现:

    发送了消息
    但是不知道什么时候结束
    也不知道有没有执行成功

    业务代码会越来越难维护。


    十二、推荐封装 IPC

    随着项目越来越大,不建议把:

    ipcMain.handle(…)

    全部写在:

    main.ts

    里面。

    例如:

    electron/
    ├── ipc/
    │ ├── app.ipc.ts
    │ ├── window.ipc.ts
    │ ├── article.ipc.ts
    │ ├── task.ipc.ts
    │ ├── account.ipc.ts
    │ └── system.ipc.ts

    ├── services/
    │ ├── article.service.ts
    │ ├── task.service.ts
    │ └── account.service.ts

    └── main.ts

    这样:

    main.ts

    ├── 注册 app IPC
    ├── 注册 article IPC
    ├── 注册 task IPC
    └── 注册 account IPC


    十四、最终推荐的通信架构

    对于一个中大型 Electron 项目,我比较推荐:

    Vue Renderer


    window.api


    Preload

    │ IPC

    Electron Main
    │ │
    │ │
    SQLite WebSocket
    │ │
    │ ↓
    │ Python Engine
    │ │
    │ Playwright
    │ │
    │ ↓
    │ CSDN


    本地数据

    其中每一层只负责自己的事情:

    层级主要职责
    Vue RendererUI、交互、页面状态
    Preload 安全暴露 API
    Electron Main 系统能力、数据库、进程管理
    Python Engine 浏览器自动化、CSDN 操作
    SQLite 本地业务数据
    WebSocket Electron 与 Python 双向通信

    十六、总结

    Electron 的核心并不是简单地把一个网页套进桌面窗口,而是一个基于多进程架构的桌面应用框架。

    开发 Electron 应用时,可以简单记住:

    Renderer
    负责 UI
    Preload
    负责安全桥接
    Main
    负责系统能力
    IPC
    负责 Renderer ↔ Main 通信
    WebSocket
    负责 Electron ↔ Python Engine 通信

    业务请求优先使用:

    ipcRenderer.invoke()

    ipcMain.handle()

    主进程主动推送状态使用:

    webContents.send()

    ipcRenderer.on()

    而对于 CSDN Auto 这样的桌面自动化软件,可以进一步采用:

    Vue

    Preload

    IPC

    Electron Main

    WebSocket

    Python Engine

    Playwright

    CSDN

    这种架构能够很好地将 UI、桌面能力、数据存储以及自动化能力 分离开来,也方便后续继续扩展 AI 写作、定时发布、多账号管理、任务队列等功能。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » Electron 进程与 IPC 通信详解:主进程、渲染进程与 Preload
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!