性能优化
本教程共 45 篇 · 第 38 篇 · 更新于 2026-08-03
38. 性能优化
Electron 应用常被人吐槽「占内存」「启动慢」。这并非框架原罪,而多源于使用方式。Electron 维护者给出了一份务实的优化清单。本章按「先测量、再优化」的原则,带你逐项排查性能陷阱。
本节目标
- 建立「先测量再优化」的性能观念。
- 避免阻塞主进程与渲染进程。
- 用按需加载与打包缩减启动耗时。
- 通过依赖审查与资源内联控制体积与内存。
- 厘清常见误区,知道哪些优化最划算。
1-1 先测量,再动手
性能优化的第一铁律是测量。凭感觉改代码往往事倍功半。最可靠的做法是:先用 Chrome DevTools 的 Performance 面板录制一次启动,找到最耗时的环节,再针对性优化。VS Code、Slack 等大型应用都靠这套「定位瓶颈 → 优化 → 再测量」的循环取得明显提升。
提示:分析多进程整体行为时,可借助 Chromium 的 Chrome Tracing 工具,它能同时观察主进程、渲染进程与 GPU 进程。
不要期待「照做几步就快」。这份清单是起点,不是终点。真正的收益来自对你自己代码的反复剖析。
1-2 小心引入模块
加一个 npm 包前,先看它的依赖体积与加载成本。某些为 Node.js 服务端写的模块,会在 require() 时读入超大配置文件或拉起一堆子依赖。曾有模块为判断「是否联网」,加载了一份十万行的端口清单 JSON,解析就要近一秒。
审查方法很简单:用 Node 直接为某个 require 生成性能与堆快照:
node --cpu-prof --heap-prof -e "require('你的模块')"
命令会在当前目录生成 .cpuprofile 与 .heapprofile,拖进 DevTools 的 Performance、Memory 面板即可分析。实测中,笨重的 request 模块加载近半秒,而 node-fetch 仅需不到 50ms、内存更小。结论:服务端好用的模块,桌面端未必合适。
1-3 别过早运行代码
应用一启动就做大量工作,是常见的卡顿来源。把昂贵的初始化延迟到真正需要时。传统写法习惯把 require 都堆在文件顶部:
// parser.js(主进程)—— 启动即同步读取磁盘
const fs = require('node:fs');
const fooParser = require('foo-parser');
class Parser {
constructor() {
this.files = fs.readdirSync('.'); // 立即执行
}
getParsedFiles() {
return fooParser.parse(this.files);
}
}
module.exports = { parser: new Parser() };
改写为按需加载:只有调用 getParsedFiles() 才碰磁盘、才 require 重模块,且用异步版本避免阻塞:
// parser.js(主进程)—— 延迟到调用时才执行
const fs = require('node:fs');
class Parser {
async getFiles() {
this.files = this.files || await fs.promises.readdir('.');
return this.files;
}
async getParsedFiles() {
const fooParser = require('foo-parser'); // 用到才加载
const files = await this.getFiles();
return fooParser.parse(files);
}
}
module.exports = { parser: new Parser() };
思路是「即时分配」,而非「启动全分配」。VS Code 打开文件时先显示无高亮的文本,再补高亮,就是同款思路。
1-4 别阻塞主进程
主进程是应用的「控制塔」,掌管窗口、交互与各进程通信,还运行着 UI 线程。绝不能用长任务阻塞它,否则整个应用会冻住。
三条守则:CPU 密集型任务用 worker_threads 或移入渲染进程,最后才考虑独立进程;尽量不用同步 IPC,也不要走已被 Electron 14 移除的 remote 模块老路;主进程里的 fs、child_process 等优先用异步版本。Electron 与 Chromium 都会把重 I/O 放到子线程,你也应如此。
1-5 别阻塞渲染进程
渲染进程跑着大量 JavaScript。要让滚动顺滑、动画稳定 60fps,需把重活挪到空闲时段或后台线程。两个利器:requestIdleCallback() 排低优先级任务;Web Workers 跑长时间 CPU 任务。这些现代 Web 平台的特性 Electron 完全支持,用法与网页一致。
1-6 移除多余 polyfill 与网络请求
Electron 内固定了 Chromium 版本,你知道确切引擎,就不必为旧浏览器 polyfill。jQuery 的很多能力已进标准 JS;async/await 也无需 regenerator-runtime。原生特性几乎总比 polyfill 快。用 TypeScript 时,把编译目标设到 Electron 支持的 ECMAScript 版本。
网络请求同样要节制。把不变的资源(字体、图片)打进安装包,别每次启动都从 CDN 拉。典型例子是 Google Fonts:桌面应用应把字体下载到本地随包发布。打开 DevTools 的 Network 面板,勾选 Disable cache 后刷新,按大小排序,把不变的大文件收进 bundle;再用网络限速模拟弱网,看哪些请求其实不必等。
1-7 打包与菜单
调用 require() 本身有开销。若能把代码打包成单文件(Webpack、Parcel、rollup 均可),开销只付一次。选打包器时注意它要能同时处理 Node.js 与浏览器环境——这正是 Electron 的特殊之处。
最后一条简单却有效:若你的应用不需要默认菜单,在 app 就绪前调用 Menu.setApplicationMenu(null),能省下构建默认菜单的开销,提升启动速度。
常见误区
- 认为 Electron 天生慢。多数卡顿来自使用方式,而非框架本身;按清单优化常有立竿见影的效果。
- 一上来就过度优化。没测量就改代码往往徒劳,先用 DevTools 找到真实瓶颈。
- 滥用同步 API。主进程里的
readFileSync、execSync会直接冻住 UI 线程。 - 忽视打包。不打包会让
require开销被重复支付,启动明显变慢。
1-8 监控长期内存
内存泄漏比启动慢更难察觉,却会随使用时间拖垮体验。用 DevTools 的 Memory 面板定期拍堆快照,对比操作前后的差异,找出只增不减的对象。常见泄漏源是事件监听器未移除、缓存无限增长、定时器未清理。养成「注册即注销」的习惯,在窗口关闭时解绑所有监听,能规避大多数泄漏。
性能优化是持续过程,不是一次性任务。把测量纳入日常,每次大改动后看一眼关键指标,应用才能长期保持轻快。
小结
性能优化没有银弹,核心是「测量 → 定位 → 优化」循环。优先处理阻塞主进程、过早加载、依赖臃肿这三处,收益最大。下一章(安全最佳实践)将从另一维度收尾本篇,讲如何守住应用的安全底线。