Electron 进程架构模型

Electron 的 JS 代码分布在两个独立的进程中:主进程(Node.js Runtime)和渲染进程(Chromium V8 Runtime)。它们不是"一个 JS 环境",而是两个完全隔离的 OS 进程,通过 IPC 协作。


一、Electron 的进程架构模型

scss 复制代码
┌─────────────────────────────────────────────────────────────┐
│                        操作系统                              │
│  ┌─────────────────────┐    ┌─────────────────────────────┐ │
│  │     主进程 (1个)      │    │      渲染进程 (N个)          │ │
│  │   Main Process       │    │    Renderer Process × N     │ │
│  │  ┌───────────────┐   │    │  ┌─────────────────────┐    │ │
│  │  │  Node.js      │   │    │  │   Chromium          │    │ │
│  │  │  Runtime      │   │◄──►│  │   ┌─────────────┐   │    │ │
│  │  │  (V8 + libuv) │   │IPC │  │   │  Blink 引擎  │   │    │ │
│  │  │               │   │    │  │   │  (DOM/CSS/JS)│   │    │ │
│  │  │  • 文件系统    │   │    │  │   └─────────────┘   │    │ │
│  │  │  • 网络请求    │   │    │  │   ┌─────────────┐   │    │ │
│  │  │  • 原生模块    │   │    │  │   │  V8 引擎    │   │    │ │
│  │  │  • 窗口管理    │   │    │  │   │ (隔离沙箱)   │   │    │ │
│  │  │  • 系统API    │   │    │  │   └─────────────┘   │    │ │
│  │  └───────────────┘   │    │  └─────────────────────┘    │ │
│  └─────────────────────┘    └─────────────────────────────┘ │
│         ▲                              ▲                    │
│         │      预加载脚本 (Preload)      │                    │
│         └──────────── 桥梁 ──────────────┘                    │
└─────────────────────────────────────────────────────────────┘

二、每个进程内部的线程模型

主进程(Main Process)

scss 复制代码
┌─────────────────────────────────────┐
│         主进程 (单个进程)             │
│  ┌─────────────────────────────┐   │
│  │      Node.js Event Loop     │   │
│  │         (libuv)             │   │
│  │  ┌─────┐ ┌─────┐ ┌─────┐   │   │
│  │  │ V8  │ │ 网络 │ │ 文件 │   │   │
│  │  │ 主线程│ │ IO  │ │ IO  │   │   │
│  │  └─────┘ └─────┘ └─────┘   │   │
│  │       ↓ 工作线程池 (libuv)   │   │
│  └─────────────────────────────┘   │
│  • 单线程事件循环(同标准 Node.js)   │
│  • 异步 IO 委托给 libuv 线程池      │
│  • 原生模块可能创建自己的线程        │
└─────────────────────────────────────┘

关键:主进程只有一个,是应用的入口和控制器。

渲染进程(Renderer Process)

scss 复制代码
┌─────────────────────────────────────────┐
│         渲染进程 (每个窗口一个)            │
│  ┌─────────────────────────────────┐   │
│  │        Chromium 多线程架构         │   │
│  │                                 │   │
│  │  ┌─────────┐  ┌─────────────┐   │   │
│  │  │ Browser │  │   Renderer  │   │   │
│  │  │ 线程    │  │   线程      │   │   │
│  │  │ (主线程)│  │ (合成/绘制)  │   │   │
│  │  └────┬────┘  └─────────────┘   │   │
│  │       │                          │   │
│  │  ┌────┴────┐  ┌─────────────┐   │   │
│  │  │   V8    │  │   IO 线程    │   │   │
│  │  │ 主线程   │  │ (网络/存储)   │   │   │
│  │  │ (执行JS) │  │             │   │   │
│  │  └─────────┘  └─────────────┘   │   │
│  │                                 │   │
│  │  • 还有 GPU 进程、扩展进程等       │   │
│  │    (Chromium 架构决定)            │   │
│  └─────────────────────────────────┘   │
└─────────────────────────────────────────┘

关键:每个 BrowserWindow 创建一个独立的渲染进程。


三、你的 JS 代码到底跑在哪?

代码位置 运行在哪个 Runtime 能做什么 不能做什么
main.js (入口) Node.js Runtime (主进程) 文件系统、网络、创建窗口、系统API 直接操作 DOM
preload.js 混合环境 (渲染进程,但有 Node.js 上下文) require() 模块、ipcRenderer 不能直接访问页面 DOM(有隔离)
页面 JS (index.html 内) Chromium V8 (渲染进程,纯浏览器环境) DOM 操作、Web API、调用 window.api require()fsos 等 Node 模块

四、预加载脚本(Preload)的关键角色

这是 Electron 架构中最容易被误解的部分:

javascript 复制代码
┌─────────────────────────────────────────────┐
│              渲染进程                         │
│  ┌─────────────────────────────────────┐   │
│  │         上下文隔离 (ContextIsolation)  │   │
│  │  ┌─────────────┐  ┌─────────────┐   │   │
│  │  │  Preload    │  │   页面 JS    │   │   │
│  │  │  上下文      │  │   上下文     │   │   │
│  │  │             │  │             │   │   │
│  │  │ • 有 Node.js│  │ • 纯浏览器   │   │   │
│  │  │ • 可 require│  │ • 无 require │   │   │
│  │  │ • 可 IPC    │  │ • 只能 Web API│   │   │
│  │  └──────┬──────┘  └──────┬──────┘   │   │
│  │         │                │           │   │
│  │         └──── contextBridge ────────┘   │   │
│  │              (安全暴露 API)               │   │
│  └─────────────────────────────────────┘   │
└─────────────────────────────────────────────┘
javascript 复制代码
// preload.js --- 运行在渲染进程,但有 Node.js 能力
const { contextBridge, ipcRenderer } = require('electron')

// 把 ipcRenderer 的能力安全地暴露给页面 JS
contextBridge.exposeInMainWorld('electronAPI', {
  readFile: (path) => ipcRenderer.invoke('fs:readFile', path),
  onUpdate: (callback) => ipcRenderer.on('update', callback)
})

// 页面 JS 中:
// window.electronAPI.readFile('/path') → 发 IPC → 主进程处理 → 返回结果

关键洞察:

  • Preload 和页面 JS 不在同一个 V8 上下文 ,但通过 contextBridge 可以安全通信。
  • 这是 Electron 的安全架构核心------防止不受信任的页面代码直接访问系统能力。

五、协作模型:消息流示例

javascript 复制代码
用户点击按钮 (渲染进程)
    │
    ▼
页面 JS: window.electronAPI.saveFile(data)
    │
    ▼
Preload: ipcRenderer.invoke('dialog:save', data) ──┐
    │                                               │
    ▼                                               │
V8 序列化消息 ──────► Chromium IPC 管道 ────────────┤
    │                                               │
    ▼                                               │
操作系统内核 IPC ─────► 主进程接收                   │
    │                                               │
    ▼                                               │
主进程: ipcMain.handle('dialog:save', async (e, data) => {
    const { filePath } = await dialog.showSaveDialog()
    await fs.writeFile(filePath, data)
    return { success: true }
})
    │
    ▼
结果反向通过 IPC 返回 ──► Preload ──► 页面 JS Promise resolve

六、与 React Native 的对比(回应你之前的类比)

维度 React Native Electron
JS 运行位置 单个进程内的 JS 引擎(Hermes/JSC) 两个独立进程(主进程 Node.js + 渲染进程 Chromium V8)
原生通信 JSI / Bridge(同进程内存共享或异步) IPC(跨进程消息,必然序列化)
JS 线程数 1 个 JS 线程 + 原生模块线程 主进程 1 个 V8 + 每个窗口 1 个 V8
渲染 Yoga 布局 + 平台原生组件 Chromium Blink 引擎直接渲染
安全模型 相对宽松(同进程) 严格进程隔离 + ContextIsolation

七、一句话总结

Electron 的 JS 代码"分身"运行在两个世界:主进程是"拥有系统权限的 Node.js 后端",渲染进程是"被沙箱隔离的 Chromium 前端"。它们通过 IPC 像微服务一样协作,预加载脚本是两者之间的安全网关。这不是"一个 JS 环境",而是"两个独立运行时通过消息协议协作"的分布式架构。

相关推荐
PHP实战开发录14 分钟前
PHP接口超时后为什么任务还在跑
开发语言·前端·php·开发
今天AI了吗24 分钟前
2026年三大AI桌面智能体横评:Codex vs Hermes vs WorkBuddy
大数据·前端·css·人工智能·架构
kill52238 分钟前
interface vs type:到底该用哪个
前端
敲代码的嘎仔1 小时前
从零实现视频续播 + 学习进度统计:前端心跳、条件更新、GROUP BY 统计全链路拆解
java·前端·数据库·学习·面试·职场和发展·音视频
做萤石二次开发的哈哈1 小时前
海康移动交通四款设备技能接入实战:布控球+取证终端+测速仪+出入口终端,Web/App/小程序移动交通应用快速生成
前端·物联网·萤石开放平台·蓝海aiot一站式工作台·aiot开发·移动交通
IT_陈寒1 小时前
我TM竟然被Java的空指针坑了第三次!
前端·人工智能·后端
xcLeigh1 小时前
AI 编程学习路线图:一份覆盖前端、后端、全栈的系统学习计划
前端·人工智能·学习
linux_cfan1 小时前
HTML5 视频交互标注实践:用开源播放器 ZWPlayer 实现热区、测验与分支节点(附接入代码)
前端·javascript·音视频
小羊没烦恼!1 小时前
Office文件的奥秘——.NET平台下不借助Office实现Word、Powerpoint等文件的解析(完)
java·大数据·前端·网络·word·powerpoint·.net
风骏时光牛马1 小时前
AI提示词工程:高效构建精准指令的方法论
前端