性能优化 #
一、性能概述 #
1.1 性能指标 #
| 指标 | 目标 | 说明 |
|---|---|---|
| 启动时间 | < 2s | 应用启动到可交互 |
| 内存占用 | < 200MB | 空闲状态内存 |
| CPU 占用 | < 5% | 空闲状态 CPU |
| 响应时间 | < 100ms | UI 交互响应 |
1.2 性能分析工具 #
javascript
// 使用 Chrome DevTools
mainWindow.webContents.openDevTools();
// 性能分析
mainWindow.webContents.openDevTools({ mode: 'detach' });
// 然后在 DevTools 中使用 Performance 和 Memory 面板
二、启动优化 #
2.1 延迟加载 #
javascript
// 延迟创建窗口
let settingsWindow = null;
function openSettings() {
if (settingsWindow) {
settingsWindow.focus();
return;
}
settingsWindow = new BrowserWindow({...});
settingsWindow.loadFile('settings.html');
}
2.2 延迟显示窗口 #
javascript
const mainWindow = new BrowserWindow({
show: false, // 先不显示
width: 800,
height: 600
});
mainWindow.loadFile('index.html');
// 页面准备好后再显示
mainWindow.once('ready-to-show', () => {
mainWindow.show();
});
2.3 预加载优化 #
javascript
// 只预加载必要的内容
const mainWindow = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
// 禁用不需要的功能
plugins: false,
webviewTag: false
}
});
2.4 启动时避免阻塞 #
javascript
// 错误:同步操作阻塞启动
app.whenReady().then(() => {
const data = fs.readFileSync('large-file.json'); // 阻塞
createWindow();
});
// 正确:异步操作
app.whenReady().then(async () => {
createWindow(); // 先创建窗口
// 后台加载数据
const data = await fs.promises.readFile('large-file.json');
mainWindow.webContents.send('data-loaded', data);
});
三、内存优化 #
3.1 减少渲染进程 #
javascript
// 避免创建过多窗口
// 复用现有窗口
const windowPool = {
main: null,
settings: null
};
function getWindow(name) {
if (windowPool[name] && !windowPool[name].isDestroyed()) {
return windowPool[name];
}
return createWindow(name);
}
3.2 及时清理资源 #
javascript
// 清理窗口引用
let mainWindow = null;
function createWindow() {
mainWindow = new BrowserWindow({...});
mainWindow.on('closed', () => {
mainWindow = null; // 清理引用
});
}
// 清理事件监听器
function setupListeners() {
const handler = () => {...};
ipcRenderer.on('event', handler);
// 不需要时移除
return () => {
ipcRenderer.removeListener('event', handler);
};
}
3.3 内存监控 #
javascript
// 监控内存使用
function logMemoryUsage() {
const memoryUsage = process.memoryUsage();
console.log({
rss: formatBytes(memoryUsage.rss),
heapTotal: formatBytes(memoryUsage.heapTotal),
heapUsed: formatBytes(memoryUsage.heapUsed),
external: formatBytes(memoryUsage.external)
});
}
function formatBytes(bytes) {
return (bytes / 1024 / 1024).toFixed(2) + ' MB';
}
// 定期检查
setInterval(logMemoryUsage, 60000);
3.4 避免内存泄漏 #
javascript
// 错误:闭包导致内存泄漏
function setupHandler() {
const largeData = getLargeData();
element.addEventListener('click', () => {
console.log(largeData); // 持有 largeData 引用
});
}
// 正确:及时清理
function setupHandler() {
const largeData = getLargeData();
const neededData = extractNeeded(largeData);
const handler = () => {
console.log(neededData);
};
element.addEventListener('click', handler);
return () => {
element.removeEventListener('click', handler);
};
}
四、渲染优化 #
4.1 减少 DOM 操作 #
javascript
// 错误:频繁 DOM 操作
function renderList(items) {
const list = document.getElementById('list');
list.innerHTML = '';
items.forEach(item => {
const li = document.createElement('li');
li.textContent = item;
list.appendChild(li); // 多次重排
});
}
// 正确:批量更新
function renderList(items) {
const list = document.getElementById('list');
const fragment = document.createDocumentFragment();
items.forEach(item => {
const li = document.createElement('li');
li.textContent = item;
fragment.appendChild(li);
});
list.innerHTML = '';
list.appendChild(fragment); // 一次重排
}
4.2 虚拟列表 #
javascript
// 虚拟列表实现
class VirtualList {
constructor(container, options) {
this.container = container;
this.itemHeight = options.itemHeight;
this.renderItem = options.renderItem;
this.items = [];
this.visibleStart = 0;
this.visibleEnd = 0;
this.init();
}
init() {
this.container.addEventListener('scroll', () => this.onScroll());
this.updateVisibleItems();
}
setItems(items) {
this.items = items;
this.container.style.height = `${items.length * this.itemHeight}px`;
this.updateVisibleItems();
}
onScroll() {
this.updateVisibleItems();
}
updateVisibleItems() {
const scrollTop = this.container.scrollTop;
const containerHeight = this.container.clientHeight;
this.visibleStart = Math.floor(scrollTop / this.itemHeight);
this.visibleEnd = Math.ceil((scrollTop + containerHeight) / this.itemHeight);
this.render();
}
render() {
const visibleItems = this.items.slice(this.visibleStart, this.visibleEnd);
// 渲染可见项
}
}
4.3 图片优化 #
javascript
// 懒加载图片
function lazyLoadImages() {
const images = document.querySelectorAll('img[data-src]');
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
observer.unobserve(img);
}
});
});
images.forEach(img => observer.observe(img));
}
4.4 CSS 优化 #
css
/* 使用 transform 代替 top/left */
.animated {
transform: translateX(100px);
}
/* 使用 will-change 提示浏览器 */
.will-animate {
will-change: transform;
}
/* 避免强制同步布局 */
.bad {
animation: resize 1s;
}
@keyframes resize {
from { width: 100px; }
to { width: 200px; }
}
五、IPC 优化 #
5.1 减少 IPC 调用 #
javascript
// 错误:频繁 IPC 调用
items.forEach(item => {
ipcRenderer.invoke('save-item', item);
});
// 正确:批量处理
ipcRenderer.invoke('save-items', items);
5.2 数据压缩 #
javascript
const zlib = require('zlib');
// 压缩大数据
async function sendLargeData(data) {
const compressed = await new Promise((resolve, reject) => {
zlib.deflate(JSON.stringify(data), (err, result) => {
if (err) reject(err);
else resolve(result);
});
});
ipcRenderer.send('large-data', compressed);
}
// 解压数据
async function receiveLargeData(compressed) {
const decompressed = await new Promise((resolve, reject) => {
zlib.inflate(compressed, (err, result) => {
if (err) reject(err);
else resolve(JSON.parse(result.toString()));
});
});
return decompressed;
}
5.3 使用共享内存 #
javascript
// 使用 sharedArrayBuffer 共享数据
const sharedBuffer = new SharedArrayBuffer(1024);
const sharedArray = new Uint8Array(sharedBuffer);
// 主进程写入
ipcMain.handle('get-shared-buffer', () => sharedBuffer);
// 渲染进程读取
const buffer = await ipcRenderer.invoke('get-shared-buffer');
const data = new Uint8Array(buffer);
六、网络优化 #
6.1 请求缓存 #
javascript
// 实现简单的请求缓存
const cache = new Map();
async function fetchWithCache(url, ttl = 60000) {
const cached = cache.get(url);
if (cached && Date.now() - cached.timestamp < ttl) {
return cached.data;
}
const response = await fetch(url);
const data = await response.json();
cache.set(url, {
data,
timestamp: Date.now()
});
return data;
}
6.2 请求合并 #
javascript
// 合并多个请求
class RequestBatcher {
constructor(batchFn, delay = 100) {
this.batchFn = batchFn;
this.delay = delay;
this.queue = [];
this.timer = null;
}
add(item) {
return new Promise((resolve) => {
this.queue.push({ item, resolve });
if (!this.timer) {
this.timer = setTimeout(() => this.flush(), this.delay);
}
});
}
async flush() {
const items = this.queue.map(q => q.item);
const results = await this.batchFn(items);
this.queue.forEach((q, i) => q.resolve(results[i]));
this.queue = [];
this.timer = null;
}
}
七、打包优化 #
7.1 代码分割 #
javascript
// 使用 Vite/Webpack 代码分割
// vite.config.js
export default {
build: {
rollupOptions: {
output: {
manualChunks: {
vendor: ['react', 'react-dom'],
utils: ['lodash', 'moment']
}
}
}
}
};
7.2 Tree Shaking #
javascript
// 只导入需要的模块
import { debounce } from 'lodash-es';
// 而不是
// import _ from 'lodash';
7.3 压缩资源 #
javascript
// electron-builder.yml
compression: maximum
files:
- "!**/*.map"
- "!**/node_modules/*/{test,__tests__,tests,examples,example}"
八、性能监控 #
8.1 性能指标收集 #
javascript
// 收集性能指标
function collectMetrics() {
const timing = performance.timing;
return {
// 页面加载时间
loadTime: timing.loadEventEnd - timing.navigationStart,
// DOM 解析时间
domReady: timing.domContentLoadedEventEnd - timing.navigationStart,
// 首次渲染时间
firstPaint: timing.responseEnd - timing.navigationStart
};
}
// 发送到分析服务
window.addEventListener('load', () => {
setTimeout(() => {
const metrics = collectMetrics();
sendMetrics(metrics);
}, 0);
});
8.2 错误监控 #
javascript
// 主进程错误监控
process.on('uncaughtException', (error) => {
console.error('未捕获异常:', error);
// 上报错误
});
process.on('unhandledRejection', (reason) => {
console.error('未处理的 Promise 拒绝:', reason);
});
// 渲染进程错误监控
window.addEventListener('error', (event) => {
console.error('渲染进程错误:', event.error);
});
window.addEventListener('unhandledrejection', (event) => {
console.error('未处理的 Promise 拒绝:', event.reason);
});
九、最佳实践 #
9.1 性能检查清单 #
markdown
- [ ] 延迟加载非关键资源
- [ ] 使用 ready-to-show 事件
- [ ] 减少 IPC 调用频率
- [ ] 及时清理事件监听器
- [ ] 使用虚拟列表处理大数据
- [ ] 压缩和优化资源
- [ ] 监控内存使用
- [ ] 收集性能指标
9.2 性能测试 #
javascript
// 使用 Chrome DevTools 进行性能测试
// 1. 打开 DevTools
// 2. 切换到 Performance 面板
// 3. 点击录制
// 4. 执行操作
// 5. 停止录制并分析
十、总结 #
10.1 核心要点 #
| 要点 | 说明 |
|---|---|
| 启动优化 | 延迟加载、延迟显示 |
| 内存优化 | 减少进程、清理资源 |
| 渲染优化 | 减少 DOM 操作、虚拟列表 |
| IPC 优化 | 批量处理、数据压缩 |
| 监控 | 收集指标、错误追踪 |
10.2 下一步 #
现在你已经掌握了性能优化技巧,接下来让我们学习 原生模块集成,深入了解 C++ 原生模块的开发!
最后更新:2026-03-28