Electron开发重点
Electron 开发重点知识体系梳理
Electron 是基于 Chromium 和 Node.js 的跨平台桌面应用开发框架,核心逻辑是用 Web 技术(HTML/CSS/JS)开发界面,同时通过 Node.js 调用原生系统能力。以下是从基础架构到工程化落地的完整知识体系梳理。
项目汇总
code/all/e-streamlabs-obs-v0.21.2x 导播助手
code/all/e-live(已下线)
code/all/e-ppt(已下线)
code/all/e-live-streaming 直播助手
code/all/e-ipub 融合出版平台
code/all/e-ysy 亿童幼师云
一、核心架构与基础概念
1. 双进程模型(核心基石)
Electron 应用由两类进程组成,二者职责严格分离,通过 IPC 通信协作:
| 进程类型 | 核心职责 | 运行环境 | 入口文件 |
|---|---|---|---|
| 主进程 (Main Process) | 应用生命周期管理、窗口创建、原生系统调用、全局状态管理 | Node.js 环境 | package.json 中 main 字段指定的文件(如 main.js) |
| 渲染进程 (Renderer Process) | 页面渲染、UI 交互、业务逻辑执行 | Chromium 环境(类似浏览器标签页) | 每个 BrowserWindow 加载的 HTML/JS 文件 |
2. 关键模块与对象
app模块:控制应用的生命周期(仅主进程可用)。BrowserWindow模块:创建和管理应用窗口(仅主进程可用)。webContents对象:渲染进程的核心对象,负责页面渲染和与渲染进程通信(主进程中通过win.webContents访问)。
二、进程间通信 (IPC) —— 开发核心难点
Electron 双进程模型下,主进程与渲染进程、渲染进程之间的通信是最频繁且最容易出错的环节,必须掌握以下模式:
1. 核心通信模块
- **
ipcMain**:主进程模块,用于监听渲染进程发送的消息。 win.webContents.send(‘channel-name’, data); 主进程发送消息给渲染进程 - **
ipcRenderer**:渲染进程模块,用于向主进程发送消息、监听主进程回复。
2. 常用通信模式
(1)渲染进程 → 主进程(单向通知)
场景:渲染进程触发主进程执行某个操作(如打开文件选择框、创建新窗口)。
1 | |
(2)渲染进程 → 主进程 → 渲染进程(双向请求/响应)
场景:渲染进程请求主进程执行异步操作并返回结果(如读取本地文件、调用系统 API)。
1 | |
(3)主进程 → 渲染进程(主动推送)
场景:主进程监听系统事件(如托盘点击、网络变化),主动通知渲染进程更新 UI。
1 | |
(4)渲染进程 <-> Webview进程
场景:渲染进程与 Webview 进程之间需要通信(如 Webview 加载完成后,渲染进程通知 Webview 执行某个操作)。
postMessage 方法:渲染进程通过 webContents.postMessage 发送消息,Webview 进程通过 window.addEventListener('message', (event) => { ... }) 监听。
在 Electron 中,<webview> 标签内的“访客”内容(即加载的第三方网页)运行在一个独立的、隔离的渲染进程中,拥有自己的 window 对象和执行环境。因此,它无法直接访问您主应用渲染进程(宿主页面)的全局对象或 IPC 通道。
核心在于渲染进程(宿主页面)如何与 webview 中的内容通信。主要有两种方式:一种是基于 postMessage 的标准 Web API,另一种是基于 Electron IPC 的专用方法。如果您希望通信双方代码耦合度低、逻辑通用,postMessage 是更合适的选择。
以下是两种通信方式的详细实现和对比:
| 通信方式 | 发送方 | 接收方 | 核心机制 | 典型使用场景 |
|---|---|---|---|---|
postMessage |
宿主页面 | webview 内页面 |
宿主页面通过 webview.executeJavaScript() 注入脚本,调用 window.postMessage 。 |
通信双方都需要监听标准的 message 事件,代码逻辑与普通网页一致。 |
webview 内页面 |
宿主页面 | webview 内页面直接调用 window.postMessage,宿主页面监听 webview 的 ipc-message 事件 。 |
用于 webview 内页面向上通知宿主页面。 |
|
| IPC (ipcRenderer) | 宿主页面 | webview 内 preload 脚本 |
宿主页面调用 webview.send() 发送 IPC 消息 。 |
webview 内页面通过 preload 脚本暴露有限的、安全的 API,进行复杂或需要 Node.js 能力的通信。 |
preload 脚本 |
宿主页面 | webview 内 preload 脚本通过 ipcRenderer.sendToHost() 回复,宿主页面监听 webview 的 ipc-message 事件 。 |
用于 preload 脚本向宿主页面发送消息。 |
方案一:基于 postMessage 的双向通信
这种方式最接近 Web 标准。关键在于宿主页面需要借助 executeJavaScript 在 webview 的上下文中执行代码,从而建立连接。
1. WebView 内页面发送消息给宿主页面
这是最直接的方式。webview 内部的网页像平时一样使用 postMessage,宿主页面通过监听 webview 标签的 ipc-message 事件来接收。
在
webview内的页面(访客页)中:1
2
3
4
5// 这是 webview 内加载的网页中的代码
function sendMessageToHost() {
// 直接向父窗口发送消息
window.postMessage({ type: 'FROM_WEBVIEW', text: 'Hello from inside!' }, '*');
}在宿主页面(渲染进程)中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20// 这是包含 <webview> 标签的页面代码
const webview = document.querySelector('webview');
webview.addEventListener('ipc-message', (event) => {
// 注意:通过 ipc-message 接收到的 event 对象结构与标准 MessageEvent 不同。
// 实际通过 postMessage 发送的复杂数据对象,需要通过其他方式(如 executeJavaScript 的回调)才能完整获取。
// 一个更可靠的方式是结合 executeJavaScript 在 webview 内设置监听器。
console.log('Received from webview:', event.channel, event.args);
});
// 更推荐的方式:通过 executeJavaScript 在 webview 内部设立监听器
webview.addEventListener('dom-ready', () => {
webview.executeJavaScript(`
window.addEventListener('message', (event) => {
// 可以将接收到的消息通过其他方式转发给宿主,例如:
console.log('Webview内部收到消息:', event.data);
// 但要将此消息发回给宿主,仍需依赖下面的“宿主页面发送消息给WebView内页面”的方法。
});
`);
});说明:直接通过
ipc-message接收postMessage的数据可能会受限。一个更稳健的模式是让宿主页面通过executeJavaScript在webview内注入一个全局函数,该函数再通过postMessage将数据传回,而宿主则通过监听同一个ipc-message来捕获。不过,下面的“宿主发送给webview”方案通常更常用。
2. 宿主页面发送消息给 WebView 内页面
宿主页面通过 executeJavaScript 在 webview 的上下文中执行代码,从而调用其内部的 postMessage 方法 。
在宿主页面(渲染进程)中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24const webview = document.querySelector('webview');
function sendMessageToWebview() {
if (webview) {
const message = { type: 'FROM_HOST', text: 'Hello from host page!' };
// 关键步骤:构造一段脚本,在 webview 内部执行 window.postMessage
const script = `window.postMessage(${JSON.stringify(message)}, '*');`;
webview.executeJavaScript(script);
}
}
// 确保 webview 已加载完成
webview.addEventListener('dom-ready', () => {
// 在 webview 内部设置一个监听器,以接收来自外部的消息
webview.executeJavaScript(`
window.addEventListener('message', (event) => {
console.log('Webview received:', event.data);
// 在这里处理接收到的消息
if (event.data.type === 'FROM_HOST') {
// ... 执行相关操作
}
});
`);
});在
webview内的页面(访客页)中:1
2
3
4
5// 这是 webview 内加载的网页中的代码,它只需要监听标准的 message 事件即可
window.addEventListener('message', (event) => {
console.log('Message received from host:', event.data);
// 处理来自宿主页面的消息
});
方案二:基于 ipcRenderer 和 preload 的双向通信
这种方式利用了 Electron 的进程间通信能力,功能更强大,但需要在 webview 上启用 nodeintegration 或通过 preload 脚本安全地暴露 API。
1. 宿主页面发送消息给 WebView(通过 webview.send)
宿主页面调用 webview.send() 发送一个 IPC 消息,该消息可以在 webview 的 preload 脚本中通过 ipcRenderer 接收 。
在宿主页面中:
1
2
3
4
5const webview = document.querySelector('webview');
webview.addEventListener('dom-ready', () => {
// 向 webview 发送 IPC 消息,频道名为 'ping'
webview.send('ping', 'Hello from host!');
});在
preload.js(为webview指定的预加载脚本)中:1
2
3
4
5
6
7
8const { ipcRenderer } = require('electron');
ipcRenderer.on('ping', (event, message) => {
console.log('Received ping in preload:', message); // 输出: Received ping in preload: Hello from host!
// 可以向宿主页面回复消息
ipcRenderer.sendToHost('pong', 'Message received in webview!');
});
2. WebView 内页面发送消息给宿主页面(通过 sendToHost)
webview 内的 preload 脚本可以通过 ipcRenderer.sendToHost() 向宿主页面发送消息,宿主页面监听 webview 的 ipc-message 事件 。
在
preload.js中:1
2
3
4
5
6const { ipcRenderer } = require('electron');
// 假设在某个时机,需要通知宿主页面
function notifyHost() {
ipcRenderer.sendToHost('custom-event', { data: 'Something happened in webview' });
}在宿主页面中:
1
2
3
4
5
6const webview = document.querySelector('webview');
webview.addEventListener('ipc-message', (event) => {
if (event.channel === 'custom-event') {
console.log('Received from webview preload:', event.args[0]); // 输出: Received from webview preload: { data: 'Something happened in webview' }
}
});Webview页面调用宿主页面转异步,800ms则为超时
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35// 获取当前页面tab信息 -- 800毫秒未响应,则定义为超时
export const getTabInfo = () => {
return new Promise((resolve, reject) => {
if (!isInTab) {
reject('当前页面不在tab页内')
}
YTIPUB.sendToHost(
JSON.stringify({
event: 'getTab',
}),
)
const listener = (event) => {
try {
if (typeof event.data !== 'string') return
const data = JSON.parse(event.data)
if (data.event === 'getTab' && typeof data.tab === 'string') {
const tab = JSON.parse(data.tab)
console.log('%c获取页面tab信息成功:', 'background: #f00', tab)
window.removeEventListener('message', listener)
resolve(tab)
}
} catch (err) {
window.removeEventListener('message', listener)
reject(err)
}
}
window.addEventListener('message', listener)
setTimeout(() => {
window.removeEventListener('message', listener)
resolve('获取tab超时')
}, 800)
})
}
(5)主进程 -> Webview进程
同(3)主进程 → 渲染进程(主动推送)
(6)Webview进程 <-> Webview进程
多标签实现时,每个标签页都是一个独立的 Webview 进程,创建时都有一个uuid,它们之间通过渲染进程中转通信。渲染进程作为中间层使用event-mitter库,负责接收来自 Webview 进程的消息广播出去或回复指定目标uuid的消息,并将其转发给其他 Webview 进程。
3. 上下文隔离下的安全通信(现代 Electron 标准做法)
为了安全,**现代 Electron 必须启用 contextIsolation 和禁用 nodeIntegration**,此时渲染进程无法直接访问 ipcRenderer,需通过 Preload 脚本 暴露安全 API:
1 | |
主进程调用
1 | |
渲染进程或Webview监听
1 | |
三、窗口与应用生命周期管理
1. BrowserWindow 窗口配置
创建窗口时的核心配置项(webPreferences 是安全重点):
1 | |
2. 窗口类型与层级
- 父子窗口:通过
parent选项创建,子窗口始终显示在父窗口上方。1
const childWin = new BrowserWindow({ parent: win, modal: true }); - 模态窗口:设置
modal: true,阻塞父窗口交互(常用于弹窗、对话框)。
对于showSaveDialogSync、showOpenDialogSync同样可以设置parent,确保对话框显示在主窗口上方。
3. 应用生命周期(app 模块事件)
掌握核心生命周期事件,控制应用启动、退出逻辑:
1 | |
3. 单例
1 | |
四、原生能力与系统交互
Electron 的核心优势是通过 Node.js 和内置模块调用原生系统能力,以下是高频使用场景:
1. 文件系统操作
主进程可直接使用 Node.js 的 fs、path 模块,结合 dialog 模块实现文件选择:
1 | |
2. 菜单与托盘
应用菜单:通过
Menu模块创建自定义菜单栏(Windows/Linux 在窗口顶部,macOS 在屏幕顶部)。1
2
3
4
5
6
7const { Menu } = require('electron');
const template = [
{ label: '文件', submenu: [{ label: '打开', click: () => console.log('打开文件') }] },
{ label: '编辑', submenu: [{ role: 'copy' }, { role: 'paste' }] } // 使用内置 role
];
const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);当然我们也可以在windows完全组件自定义,不使用Menu,Dom节点上配置样式即可
1
-webkit-app-region: drag; // no-drag系统托盘:通过
Tray模块添加系统托盘图标和右键菜单。1
2
3
4
5
6
7
8const { Tray, Menu } = require('electron');
const tray = new Tray('path/to/icon.png');
const contextMenu = Menu.buildFromTemplate([
{ label: '显示窗口', click: () => win.show() },
{ label: '退出', click: () => app.quit() }
]);
tray.setToolTip('My Electron App');
tray.setContextMenu(contextMenu);
3. 系统集成
- 通知:使用 HTML5
NotificationAPI(渲染进程)或 Node.js 模块(主进程)。 - 剪贴板:通过
clipboard模块读写系统剪贴板。 - 外部链接:通过
shell模块在默认浏览器中打开链接(避免在 Electron 窗口中打开外部页面)。1
2const { shell } = require('electron');
shell.openExternal('https://github.com');
3. 注册系统协议
1 | |
4. 注册文件扩展
1 | |
五、工程化:打包与分发
开发完成后,需将 Electron 应用打包为各平台的安装包(.exe、.dmg、.AppImage 等),**electron-builder** 是目前最主流的打包工具。
1. 快速配置
在 package.json 中添加 build 配置:
1 | |
windows签名
配置electron.builder配置,获取打包签名配置
1 | |
macOS签名 & linux签名-统信UOS、麒麟
以下是 electron-builder 针对 macOS 和 Linux 的签名配置详细指南,分为两部分说明:
一、macOS 签名与公证配置
macOS 签名分为两步:代码签名(Code Signing) 和 公证(Notarization)(macOS 10.14.5+ 必须公证才能在未授权设备上运行)。
1. 前置准备
- Apple Developer 账号:需加入 Apple Developer Program(年费 99 美元)。
- 证书创建:
- 登录 Apple Developer 证书页面。
- 创建
Developer ID Application类型的证书(用于发布到 App Store 外的应用)。 - 下载证书并双击安装到 Mac 的 Keychain(钥匙串访问)中。
- 公证所需信息:
- Apple ID(邮箱)。
- App-specific 密码:在 Apple ID 管理页 生成(用于替代主密码,避免泄露)。
- Team ID:在 Apple Developer 会员详情页查看。
2. 基础签名配置
在 electron-builder 配置中添加 mac 签名相关字段:
1 | |
补充说明:
环境变量替代方案(推荐用于 CI/CD):
CSC_NAME:证书名称(如Developer ID Application: ...)。CSC_LINK:证书文件路径(.p12 格式),配合CSC_KEY_PASSWORD使用。APPLE_ID:Apple ID 邮箱。APPLE_ID_PASSWORD:App-specific 密码。APPLE_TEAM_ID:Team ID。
entitlements.mac.plist 示例(需根据应用权限调整):
1
2
3
4
5
6
7
8
9
10
11
12<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
</dict>
</plist>
二、Linux 签名配置(以 deb 包为例)
Linux 签名主要针对 .deb 包(Debian/Ubuntu 系),使用 GPG 密钥 签名,确保包的完整性。
1. 前置准备
生成 GPG 密钥对(若已有可跳过):
1
gpg --gen-key按提示输入姓名、邮箱等信息,生成密钥对(公钥和私钥)。
导出公钥(用于用户验证包):
1
gpg --armor --export your-email@example.com > public-key.asc将
public-key.asc分发给用户,用户可通过sudo apt-key add public-key.asc导入信任。
2. electron-builder 配置
在 linux 配置中添加签名相关字段:
1 | |
补充说明:
环境变量替代方案(推荐用于 CI/CD):
GPG_SIGNER_ID:GPG 密钥的 ID(可通过gpg --list-secret-keys查看)。GPG_PASSPHRASE:GPG 密钥的密码(若设置了)。GPG_EXECUTABLE:GPG 可执行文件路径(默认gpg)。
签名验证:用户安装
.deb包时,若已导入公钥,会自动验证签名;未导入时会提示警告,需用户手动确认。
三、注意事项
- macOS 公证超时:若公证过程超时,可尝试增加
notarize.timeout配置(单位:秒)。 - Linux 多架构签名:若同时构建
x64和arm64包,确保 GPG 密钥对两种架构均有效。 - CI/CD 集成:
- macOS:将证书导出为
.p12文件,通过CSC_LINK和CSC_KEY_PASSWORD传入 CI。 - Linux:将 GPG 私钥导出为文件,通过
GPG_PRIVATE_KEY环境变量传入 CI(需 Base64 编码)。
- macOS:将证书导出为
2. 自动更新
使用 electron-updater 实现应用自动更新(需配合静态文件服务器或 GitHub Releases):
1 | |
3. 崩溃上报及分析
- 崩溃上报:使用
electron-crash-reporter或electron-builder自动上报崩溃信息。 - 日志记录:在主进程中使用
electron-log库记录运行时日志,方便调试。
4. 日志上报
- 日志记录:在主进程中使用
electron-log库记录运行时日志,方便调试。 - 日志上报:将日志上传到服务器,分析崩溃原因(如 阿里云Arms、Sentry、Loggly 等)。
六、性能优化与安全
1. 性能优化重点
- 渲染进程性能:
- 避免在主线程执行 heavy 计算,使用
Web Workers。 - 优化 DOM 操作,使用虚拟滚动处理长列表。
- 减少不必要的重绘重排,使用 CSS
transform和opacity做动画,硬件加速。
- 避免在主线程执行 heavy 计算,使用
- 主进程性能:
- 避免在主进程执行阻塞操作(如同步文件读写),尽量使用异步 API。
- 合理使用
BrowserWindow的show: false预加载窗口,提升打开速度。
- 内存管理:
- 及时关闭不再使用的窗口,避免内存泄漏。
- 移除不再需要的 IPC 监听器(
ipcRenderer.removeListener)。
2. 安全红线(必须遵守)
Electron 应用的安全漏洞可能导致远程代码执行,以下是强制安全配置:
- **始终禁用
nodeIntegration**,启用contextIsolation。 - 使用 Preload 脚本 暴露 API,禁止直接在渲染进程使用 Node.js。
- 禁止加载不受信任的远程内容,若必须加载,启用
webSecurity(默认开启)。 - **设置 Content Security Policy (CSP)**,在 HTML 中添加:
1
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'"> - 避免使用
remote模块(已弃用),改用 IPC 通信。
七、调试与常见问题
1. 调试技巧
- 渲染进程调试:打开 DevTools(
win.webContents.openDevTools()),和 Chrome 调试一致。 - 主进程调试:使用
--inspect启动应用,通过 Chrome DevTools 连接:然后在 Chrome 中访问1
electron --inspect=5858 main.jschrome://inspect进行调试。
2. 常见坑点
- 跨域问题:渲染进程加载远程接口时可能遇到 CORS,可在主进程通过
webRequest模块修改响应头,或配置代理。 - 路径问题:打包后文件路径变化,使用
path.join(__dirname, 'file.txt')而非相对路径。 - macOS 签名与公证:macOS 应用必须签名和公证才能在非开发者机器上运行,需在
electron-builder中配置证书。
3. 性能检测
有的,既有成熟的开源项目可以直接使用,也可以结合你提供的代码进行扩展实现。以下是详细方案:
一、推荐开源项目
1. electron-process-manager
- 功能:类似 Chrome 任务管理器的 UI 工具,实时展示所有进程(主进程、渲染进程、GPU 进程等)的 CPU、内存占用,支持杀死进程、打开 DevTools。
- 适用场景:开发阶段快速定位高资源占用进程。
- 引用:[1]
2. Devtron
- 功能:Electron 官方调试工具扩展,提供 IPC 消息监控、依赖关系图、事件检查器等。
- 适用场景:调试 IPC 通信、事件监听器泄漏等问题。
- 引用:[6]
3. Debugtron
- 功能:专门用于生产环境的实时调试工具,支持性能分析、错误捕获、日志管理。
- 适用场景:生产环境问题排查。
- 引用:[2]
自定义性能监控的代码示例
1 | |
总结
- 快速上手:推荐先用
Devtron+electron-process-manager覆盖基础监控需求。 - 自定义扩展:在你现有代码基础上,按上述建议修复参数、增加资源限制、补充 Electron 进程指标,可实现更完善的自定义监控。、
4. 崩溃上报及分析
代码示例
1 | |
Dump 文件分析方法
崩溃生成的 .dmp 文件(minidump)需要符号化才能还原出调用栈,以下是常用分析方案:
方案 1:使用 Electron 官方符号 + minidump_stackwalk(本地分析)
步骤:
下载 Electron 符号文件
从 Electron 发布页 下载对应版本的symbols.zip(如electron-v28.0.0-darwin-x64-symbols.zip),解压得到.pdb(Windows)或.sym(macOS/Linux)文件。安装 Breakpad 工具
下载minidump_stackwalk(Breakpad 工具集的一部分):- Windows/macOS/Linux 可从 mozilla/breakpad 编译或找预编译版本。
运行分析命令
1
minidump_stackwalk your_crash.dmp /path/to/symbols > crash_stack.txt输出的
crash_stack.txt中会包含符号化后的调用栈。
方案 2:使用第三方服务(推荐,生产环境)
无需手动处理符号,直接上传 dump 文件即可自动分析:
- Sentry:支持 Electron 崩溃上报,自动符号化调用栈(需配置符号文件上传)。
- Backtrace:专门针对 Electron 优化,支持实时崩溃监控和深度分析。
- BugSplat:提供 Electron SDK,一键集成崩溃报告和分析。
方案 3:使用 Electron 的 crashReporter 配合 Socorro(自建服务)
若需自建服务,可使用 Mozilla 的 Socorro(Electron 文档推荐),但部署复杂度较高,适合大型团队。
4. Web worker
以下是 Node.js 中 Web Workers(worker_threads 模块) 的完整示例,包含主线程与工作线程的通信、错误处理等核心功能。
一、核心概念
Node.js 的 worker_threads 模块允许在独立线程中执行 JavaScript 代码,避免 CPU 密集型任务阻塞主线程(事件循环)。
- 主线程:创建 Worker、管理线程生命周期、与 Worker 通信。
- 工作线程:执行耗时任务、通过消息传递与主线程交互。
二、完整示例
我们将实现一个「计算斐波那契数列」的场景(CPU 密集型任务),通过 Worker 避免阻塞主线程。
1. 项目结构
1 | |
2. 主线程代码(main.js)
负责创建 Worker、发送任务数据、接收结果并处理错误。
1 | |
3. 工作线程代码(worker.js)
接收主线程任务、执行计算、返回结果。
1 | |
三、运行示例
- 确保已安装 Node.js(建议 v12+,
worker_threads从 v10.5.0 开始实验性支持,v12+ 稳定)。 - 在项目目录下执行:
1
node main.js
预期输出
1 | |
四、进阶用法:传递复杂数据与共享内存
1. 传递对象(自动序列化)
Worker 之间传递对象时,会通过 结构化克隆算法 序列化(类似 JSON.parse(JSON.stringify()),但支持更多类型,如 Date、RegExp)。
1 | |
2. 共享内存(SharedArrayBuffer)
若需高效共享大量数据,可使用 SharedArrayBuffer(避免序列化开销),但需注意线程安全(配合 Atomics 操作)。
1 | |
五、注意事项
- 不能直接共享变量:Worker 有独立的内存空间,只能通过消息传递或
SharedArrayBuffer共享数据。 - 序列化开销:传递大对象时,结构化克隆会有性能损耗,此时优先考虑
SharedArrayBuffer。 - Worker 数量限制:避免创建过多 Worker(建议不超过 CPU 核心数),否则线程切换开销会抵消收益。
- 模块支持:Worker 中可使用
require()或 ESMimport,但部分 Node.js API(如cluster模块)不可用。