外观
Electron 性能优化
性能优化概述
Electron 应用性能优化是一个系统工程,涉及启动速度、运行时性能、内存管理和资源使用等多个维度。由于 Electron 应用同时包含 Node.js 后端环境和 Chromium 前端环境,性能优化需要在这两个层面协同进行。优化的核心目标是实现更快的启动、更低的内存占用和更流畅的用户体验。
Electron 性能瓶颈的典型分布:
启动阶段
├── 应用初始化延迟
├── 窗口创建耗时
└── 前端资源加载
运行阶段
├── 内存泄漏
├── 渲染性能
├── IPC 通信开销
└── 背景资源占用启动性能优化
应用启动流程优化
优化 Electron 应用的启动流程,减少从启动到可交互的时间。
javascript
// main.js - 启动优化配置
import { app, BrowserWindow } from 'electron';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
class StartupOptimizer {
constructor() {
this.startTime = Date.now();
this.optimizeAppConfig();
}
optimizeAppConfig() {
// 禁用硬件加速(根据需求选择)
// app.disableHardwareAcceleration();
// 设置应用单例锁
if (!app.requestSingleInstanceLock()) {
app.quit();
return;
}
// 预加载关键模块
this.preloadCriticalModules();
}
preloadCriticalModules() {
// 预加载常用 Node.js 模块
require('fs');
require('path');
require('url');
}
async createOptimizedWindow() {
const windowOptions = {
width: 1200,
height: 800,
show: false, // 初始不显示,等待准备完成
backgroundColor: '#2e2e2e', // 避免白色闪屏
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
enableRemoteModule: false,
preload: join(dirname(fileURLToPath(import.meta.url)), 'preload.js'),
// 性能相关配置
offscreen: false,
webgl: false, // 按需开启
plugins: false,
// 启用实验性功能提升性能
experimentalFeatures: false,
// 禁用不需要的功能
navigateOnDragDrop: false,
enablePreferredSize: false
}
};
const mainWindow = new BrowserWindow(windowOptions);
// 优化加载事件处理
this.setupWindowEvents(mainWindow);
return mainWindow;
}
setupWindowEvents(window) {
// 使用 ready-to-show 事件,避免显示空白窗口
window.once('ready-to-show', () => {
const loadTime = Date.now() - this.startTime;
console.log(`🔄 应用启动耗时: ${loadTime}ms`);
window.show();
window.focus();
// 开发环境下显示性能信息
if (process.env.NODE_ENV === 'development') {
this.logPerformanceMetrics();
}
});
// 优化页面加载
window.webContents.on('did-finish-load', () => {
this.injectPerformanceOptimizations(window);
});
}
logPerformanceMetrics() {
const metrics = {
platform: process.platform,
arch: process.arch,
memory: process.memoryUsage(),
versions: process.versions
};
console.log('📊 启动性能指标:', metrics);
}
injectPerformanceOptimizations(window) {
// 注入性能优化脚本
window.webContents.executeJavaScript(`
// 禁用开发者工具快捷键(生产环境)
if (process.env.NODE_ENV === 'production') {
document.addEventListener('keydown', (e) => {
if (e.key === 'F12' || (e.ctrlKey && e.shiftKey && e.key === 'I')) {
e.preventDefault();
}
});
}
// 性能监控
window.performanceMark('first-contentful-paint');
`);
}
}
// 应用启动优化
const startupOptimizer = new StartupOptimizer();
app.whenReady().then(async () => {
const mainWindow = await startupOptimizer.createOptimizedWindow();
// 加载应用页面
if (process.env.NODE_ENV === 'development') {
await mainWindow.loadURL('http://localhost:3000');
} else {
await mainWindow.loadFile('dist/index.html');
}
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});代码分割与懒加载
使用现代前端构建工具的代码分割功能,减少初始加载体积。
javascript
// src/utils/lazy-loading.js
export class LazyLoader {
constructor() {
this.loadedModules = new Map();
this.loadingPromises = new Map();
}
// 动态导入模块
async loadModule(modulePath, moduleName) {
if (this.loadedModules.has(moduleName)) {
return this.loadedModules.get(moduleName);
}
if (this.loadingPromises.has(moduleName)) {
return this.loadingPromises.get(moduleName);
}
const loadPromise = import(modulePath)
.then(module => {
this.loadedModules.set(moduleName, module);
this.loadingPromises.delete(moduleName);
console.log(`✅ 懒加载模块: ${moduleName}`);
return module;
})
.catch(error => {
this.loadingPromises.delete(moduleName);
console.error(`❌ 加载模块失败: ${moduleName}`, error);
throw error;
});
this.loadingPromises.set(moduleName, loadPromise);
return loadPromise;
}
// 预加载非关键模块
preloadModules(moduleMap) {
if ('requestIdleCallback' in window) {
requestIdleCallback(() => {
Object.entries(moduleMap).forEach(([name, path]) => {
this.loadModule(path, name);
});
});
} else {
// 降级方案
setTimeout(() => {
Object.entries(moduleMap).forEach(([name, path]) => {
this.loadModule(path, name);
});
}, 3000);
}
}
}
// 使用示例
export const lazyLoader = new LazyLoader();
// 路由级别的代码分割
export const routes = {
home: () => lazyLoader.loadModule('./components/Home.js', 'Home'),
settings: () => lazyLoader.loadModule('./components/Settings.js', 'Settings'),
analytics: () => lazyLoader.loadModule('./components/Analytics.js', 'Analytics')
};
// 预加载配置
export const preloadConfig = {
'ChartLibrary': './libs/charts.js',
'DataGrid': './libs/data-grid.js',
'RichEditor': './libs/rich-editor.js'
};javascript
// src/components/Router.js
import { lazyLoader, routes, preloadConfig } from '../utils/lazy-loading.js';
export class Router {
constructor() {
this.currentRoute = null;
this.init();
}
init() {
// 初始加载后预加载其他模块
lazyLoader.preloadModules(preloadConfig);
// 路由事件监听
this.setupRouteListeners();
}
async navigateTo(routeName) {
if (this.currentRoute === routeName) return;
try {
// 显示加载状态
this.showLoading();
// 动态加载路由组件
const module = await routes[routeName]();
// 渲染组件
this.renderComponent(module.default);
this.currentRoute = routeName;
// 更新页面标题等
this.updatePageMetadata(routeName);
} catch (error) {
console.error('路由导航失败:', error);
this.showError('页面加载失败');
} finally {
this.hideLoading();
}
}
showLoading() {
// 显示加载指示器
const loader = document.getElementById('page-loader');
if (loader) loader.style.display = 'block';
}
hideLoading() {
const loader = document.getElementById('page-loader');
if (loader) loader.style.display = 'none';
}
renderComponent(Component) {
const app = document.getElementById('app');
if (app) {
app.innerHTML = '';
const component = new Component();
if (typeof component.render === 'function') {
app.appendChild(component.render());
}
}
}
setupRouteListeners() {
// 链接点击事件委托
document.addEventListener('click', (e) => {
const link = e.target.closest('[data-route]');
if (link) {
e.preventDefault();
const routeName = link.dataset.route;
this.navigateTo(routeName);
}
});
// 浏览器前进后退
window.addEventListener('popstate', (e) => {
const routeName = this.getRouteFromPath(window.location.pathname);
this.navigateTo(routeName);
});
}
}内存管理优化
内存泄漏检测与预防
实现系统化的内存泄漏检测和预防机制。
javascript
// src/utils/memory-manager.js
export class MemoryManager {
constructor() {
this.monitoringInterval = null;
this.leakThreshold = 10 * 1024 * 1024; // 10MB
this.snapshots = [];
this.eventListeners = new WeakMap();
}
startMonitoring(interval = 30000) {
if (this.monitoringInterval) return;
this.monitoringInterval = setInterval(() => {
this.takeMemorySnapshot();
this.checkForLeaks();
}, interval);
console.log('🧠 内存监控已启动');
}
stopMonitoring() {
if (this.monitoringInterval) {
clearInterval(this.monitoringInterval);
this.monitoringInterval = null;
console.log('🧠 内存监控已停止');
}
}
takeMemorySnapshot() {
if (performance.memory) {
const snapshot = {
timestamp: Date.now(),
used: performance.memory.usedJSHeapSize,
total: performance.memory.totalJSHeapSize,
limit: performance.memory.jsHeapSizeLimit
};
this.snapshots.push(snapshot);
// 保持最近50个快照
if (this.snapshots.length > 50) {
this.snapshots.shift();
}
return snapshot;
}
return null;
}
checkForLeaks() {
if (this.snapshots.length < 2) return;
const recent = this.snapshots[this.snapshots.length - 1];
const previous = this.snapshots[this.snapshots.length - 2];
const growth = recent.used - previous.used;
if (growth > this.leakThreshold) {
console.warn('⚠️ 检测到可能的内存泄漏:', {
增长量: `${(growth / 1024 / 1024).toFixed(2)} MB`,
当前使用: `${(recent.used / 1024 / 1024).toFixed(2)} MB`,
时间间隔: `${(recent.timestamp - previous.timestamp) / 1000} 秒`
});
this.analyzePotentialLeaks();
}
}
analyzePotentialLeaks() {
// 检查常见的内存泄漏模式
this.checkDetachedDOMNodes();
this.checkEventListenerLeaks();
this.checkTimerLeaks();
}
checkDetachedDOMNodes() {
// 检查分离的DOM节点
const detachedNodes = [];
const walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_ELEMENT,
null,
false
);
let node;
while (node = walker.nextNode()) {
if (!document.body.contains(node)) {
detachedNodes.push(node);
}
}
if (detachedNodes.length > 0) {
console.warn(`发现 ${detachedNodes.length} 个分离的DOM节点`);
}
}
checkEventListenerLeaks() {
// 简化的事件监听器泄漏检查
const elements = document.querySelectorAll('*');
let totalListeners = 0;
elements.forEach(element => {
// 这里可以扩展更详细的事件监听器检查
if (element._events) {
totalListeners += Object.keys(element._events).length;
}
});
if (totalListeners > 1000) { // 阈值
console.warn(`检测到大量事件监听器: ${totalListeners}`);
}
}
checkTimerLeaks() {
// 检查未清理的定时器
const timerCount = this.getActiveTimersCount();
if (timerCount > 50) {
console.warn(`检测到大量活跃定时器: ${timerCount}`);
}
}
getActiveTimersCount() {
// 通过重写 setTimeout 和 setInterval 来跟踪
return window._activeTimers ? window._activeTimers.size : 0;
}
// 安全的事件监听器包装
safeAddEventListener(element, event, handler, options) {
const wrappedHandler = (...args) => {
try {
return handler(...args);
} catch (error) {
console.error('事件处理器错误:', error);
}
};
element.addEventListener(event, wrappedHandler, options);
// 跟踪监听器以便后续清理
if (!this.eventListeners.has(element)) {
this.eventListeners.set(element, []);
}
this.eventListeners.get(element).push({ event, handler: wrappedHandler });
return () => {
element.removeEventListener(event, wrappedHandler, options);
const listeners = this.eventListeners.get(element);
if (listeners) {
const index = listeners.findIndex(l => l.handler === wrappedHandler);
if (index > -1) {
listeners.splice(index, 1);
}
}
};
}
// 清理所有跟踪的事件监听器
cleanupEventListeners(element) {
const listeners = this.eventListeners.get(element);
if (listeners) {
listeners.forEach(({ event, handler }) => {
element.removeEventListener(event, handler);
});
this.eventListeners.delete(element);
}
}
getMemoryStats() {
if (performance.memory) {
return {
used: `${(performance.memory.usedJSHeapSize / 1024 / 1024).toFixed(2)} MB`,
total: `${(performance.memory.totalJSHeapSize / 1024 / 1024).toFixed(2)} MB`,
limit: `${(performance.memory.jsHeapSizeLimit / 1024 / 1024).toFixed(2)} MB`,
usage: `${((performance.memory.usedJSHeapSize / performance.memory.jsHeapSizeLimit) * 100).toFixed(1)}%`
};
}
return { error: '内存API不可用' };
}
}
// 全局内存管理器实例
export const memoryManager = new MemoryManager();
// 启动内存监控(开发环境)
if (process.env.NODE_ENV === 'development') {
memoryManager.startMonitoring();
}资源生命周期管理
javascript
// src/utils/resource-manager.js
export class ResourceManager {
constructor() {
this.resources = new Map();
this.cache = new Map();
this.cleanupCallbacks = new Map();
}
// 注册资源并自动管理生命周期
registerResource(id, resource, cleanupCallback) {
this.resources.set(id, resource);
if (cleanupCallback) {
this.cleanupCallbacks.set(id, cleanupCallback);
}
return id;
}
// 获取资源
getResource(id) {
return this.resources.get(id);
}
// 释放资源
releaseResource(id) {
const resource = this.resources.get(id);
const cleanupCallback = this.cleanupCallbacks.get(id);
if (cleanupCallback && resource) {
cleanupCallback(resource);
}
this.resources.delete(id);
this.cleanupCallbacks.delete(id);
console.log(`🗑️ 释放资源: ${id}`);
}
// 批量释放资源
releaseResources(ids) {
ids.forEach(id => this.releaseResource(id));
}
// 释放所有资源
releaseAll() {
const resourceIds = Array.from(this.resources.keys());
resourceIds.forEach(id => this.releaseResource(id));
console.log(`🗑️ 释放所有资源: ${resourceIds.length} 个`);
}
// 缓存管理
setCache(key, value, ttl = 300000) { // 默认5分钟
const cacheItem = {
value,
timestamp: Date.now(),
ttl
};
this.cache.set(key, cacheItem);
return value;
}
getCache(key) {
const item = this.cache.get(key);
if (!item) return null;
// 检查是否过期
if (Date.now() - item.timestamp > item.ttl) {
this.cache.delete(key);
return null;
}
return item.value;
}
clearExpiredCache() {
const now = Date.now();
let clearedCount = 0;
for (const [key, item] of this.cache.entries()) {
if (now - item.timestamp > item.ttl) {
this.cache.delete(key);
clearedCount++;
}
}
if (clearedCount > 0) {
console.log(`🧹 清理过期缓存: ${clearedCount} 项`);
}
}
// 图片资源懒加载
createLazyImageLoader() {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
const src = img.dataset.src;
if (src) {
img.src = src;
img.classList.remove('lazy');
observer.unobserve(img);
}
}
});
});
return observer;
}
// 预加载关键资源
preloadCriticalResources() {
const criticalResources = [
'/fonts/main.woff2',
'/css/critical.css',
'/images/logo.svg'
];
criticalResources.forEach(resource => {
this.preloadResource(resource);
});
}
preloadResource(url) {
const link = document.createElement('link');
link.rel = 'preload';
link.href = url;
if (url.endsWith('.woff2')) {
link.as = 'font';
link.type = 'font/woff2';
link.crossOrigin = 'anonymous';
} else if (url.endsWith('.css')) {
link.as = 'style';
} else if (url.endsWith('.js')) {
link.as = 'script';
} else {
link.as = 'image';
}
document.head.appendChild(link);
}
}
export const resourceManager = new ResourceManager();
// 自动清理过期缓存
setInterval(() => {
resourceManager.clearExpiredCache();
}, 60000); // 每分钟清理一次渲染性能优化
虚拟滚动与列表优化
javascript
// src/components/VirtualScroll.js
export class VirtualScroll {
constructor(container, options = {}) {
this.container = container;
this.itemHeight = options.itemHeight || 50;
this.overscan = options.overscan || 5;
this.items = options.items || [];
this.renderItem = options.renderItem;
this.visibleStart = 0;
this.visibleEnd = 0;
this.visibleItems = [];
this.init();
}
init() {
this.setupContainer();
this.calculateVisibleRange();
this.renderVisibleItems();
this.setupScrollListener();
}
setupContainer() {
this.container.style.overflowY = 'auto';
this.container.style.position = 'relative';
// 设置容器高度以启用滚动
this.container.style.height = `${this.container.clientHeight}px`;
// 创建内容包装器
this.content = document.createElement('div');
this.content.style.position = 'relative';
this.content.style.height = `${this.items.length * this.itemHeight}px`;
this.container.appendChild(this.content);
}
calculateVisibleRange() {
const scrollTop = this.container.scrollTop;
const visibleHeight = this.container.clientHeight;
this.visibleStart = Math.max(0, Math.floor(scrollTop / this.itemHeight) - this.overscan);
this.visibleEnd = Math.min(
this.items.length,
Math.ceil((scrollTop + visibleHeight) / this.itemHeight) + this.overscan
);
}
renderVisibleItems() {
// 移除不可见的项目
this.visibleItems.forEach(item => {
if (item.index < this.visibleStart || item.index >= this.visibleEnd) {
item.element.remove();
}
});
// 更新可见项目数组
this.visibleItems = this.visibleItems.filter(item =>
item.index >= this.visibleStart && item.index < this.visibleEnd
);
// 添加新可见的项目
for (let i = this.visibleStart; i < this.visibleEnd; i++) {
const existingItem = this.visibleItems.find(item => item.index === i);
if (!existingItem) {
const itemElement = this.renderItem(this.items[i], i);
itemElement.style.position = 'absolute';
itemElement.style.top = `${i * this.itemHeight}px`;
itemElement.style.width = '100%';
itemElement.style.height = `${this.itemHeight}px`;
this.content.appendChild(itemElement);
this.visibleItems.push({ index: i, element: itemElement });
}
}
}
setupScrollListener() {
let scrollTimeout;
this.container.addEventListener('scroll', () => {
// 防抖处理
clearTimeout(scrollTimeout);
scrollTimeout = setTimeout(() => {
this.calculateVisibleRange();
this.renderVisibleItems();
}, 16); // 约60fps
});
}
updateItems(newItems) {
this.items = newItems;
this.content.style.height = `${this.items.length * this.itemHeight}px`;
this.calculateVisibleRange();
this.renderVisibleItems();
}
// 性能监控
getPerformanceStats() {
return {
totalItems: this.items.length,
visibleItems: this.visibleItems.length,
renderStart: this.visibleStart,
renderEnd: this.visibleEnd,
memoryUsage: performance.memory ? {
used: `${(performance.memory.usedJSHeapSize / 1024 / 1024).toFixed(2)} MB`
} : null
};
}
}
// 使用示例
export function createOptimizedList(containerId, data, renderFunction) {
const container = document.getElementById(containerId);
const virtualScroll = new VirtualScroll(container, {
itemHeight: 60,
overscan: 10,
items: data,
renderItem: renderFunction
});
return virtualScroll;
}动画与渲染优化
javascript
// src/utils/animation-optimizer.js
export class AnimationOptimizer {
constructor() {
this.animations = new Map();
this.rafCallbacks = new Map();
}
// 使用 requestAnimationFrame 优化动画
optimizedAnimation(callback, element = null) {
let animationId;
const animate = (timestamp) => {
callback(timestamp);
animationId = requestAnimationFrame(animate);
};
animationId = requestAnimationFrame(animate);
// 跟踪动画以便后续清理
if (element) {
if (!this.animations.has(element)) {
this.animations.set(element, []);
}
this.animations.get(element).push(animationId);
}
return animationId;
}
// 停止元素的所有动画
stopAnimations(element) {
const animations = this.animations.get(element);
if (animations) {
animations.forEach(id => cancelAnimationFrame(id));
this.animations.delete(element);
}
}
// 使用 CSS transform 代替直接修改位置
transformElement(element, translateX = 0, translateY = 0, scale = 1) {
element.style.transform = `translate3d(${translateX}px, ${translateY}px, 0) scale(${scale})`;
}
// 批量DOM操作
batchDOMUpdates(callback) {
// 使用 requestAnimationFrame 批量更新
requestAnimationFrame(() => {
callback();
});
}
// 防抖滚动处理
createDebouncedScrollHandler(callback, delay = 16) {
let timeoutId;
return (event) => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
callback(event);
}, delay);
};
}
// 使用 will-change 提示浏览器优化
optimizeForAnimation(element, properties = ['transform', 'opacity']) {
element.style.willChange = properties.join(', ');
// 动画完成后移除 will-change
return () => {
element.style.willChange = 'auto';
};
}
// 检测帧率
startFPSCounter(callback, duration = 1000) {
let frames = 0;
let startTime = performance.now();
const countFrame = () => {
frames++;
const currentTime = performance.now();
if (currentTime - startTime >= duration) {
const fps = Math.round((frames * 1000) / (currentTime - startTime));
callback(fps);
frames = 0;
startTime = currentTime;
}
requestAnimationFrame(countFrame);
};
countFrame();
}
}
export const animationOptimizer = new AnimationOptimizer();
// 使用示例
export function createSmoothScroll(container) {
let targetScroll = container.scrollTop;
let currentScroll = targetScroll;
const scrollHandler = animationOptimizer.optimizedAnimation(() => {
const diff = targetScroll - currentScroll;
if (Math.abs(diff) < 1) {
currentScroll = targetScroll;
} else {
currentScroll += diff * 0.1; // 缓动效果
}
container.scrollTop = currentScroll;
}, container);
return {
scrollTo: (position) => {
targetScroll = position;
},
destroy: () => {
animationOptimizer.stopAnimations(container);
}
};
}IPC 通信优化
高效的进程间通信
javascript
// src/utils/ipc-optimizer.js
export class IPCOptimizer {
constructor() {
this.pendingRequests = new Map();
this.batchQueue = new Map();
this.batchTimeout = 16; // 16ms 批处理间隔
this.cache = new Map();
}
// 批处理 IPC 调用
batchedInvoke(channel, data, options = {}) {
const cacheKey = options.cacheKey || this.generateCacheKey(channel, data);
// 检查缓存
if (options.cache && this.cache.has(cacheKey)) {
return Promise.resolve(this.cache.get(cacheKey));
}
// 添加到批处理队列
if (!this.batchQueue.has(channel)) {
this.batchQueue.set(channel, []);
// 设置批处理超时
setTimeout(() => {
this.processBatch(channel);
}, this.batchTimeout);
}
return new Promise((resolve, reject) => {
this.batchQueue.get(channel).push({ data, resolve, reject, cacheKey });
});
}
processBatch(channel) {
const batch = this.batchQueue.get(channel);
if (!batch || batch.length === 0) return;
this.batchQueue.delete(channel);
const batchData = batch.map(item => item.data);
// 发送批处理请求
window.electronAPI.invokeBatch(channel, batchData)
.then(results => {
batch.forEach((item, index) => {
const result = results[index];
// 缓存结果
if (item.cacheKey) {
this.cache.set(item.cacheKey, result);
}
item.resolve(result);
});
})
.catch(error => {
batch.forEach(item => {
item.reject(error);
});
});
}
// 生成缓存键
generateCacheKey(channel, data) {
return `${channel}:${JSON.stringify(data)}`;
}
// 清理缓存
clearCache(pattern = null) {
if (pattern) {
for (const key of this.cache.keys()) {
if (key.includes(pattern)) {
this.cache.delete(key);
}
}
} else {
this.cache.clear();
}
}
// 带超时的 IPC 调用
invokeWithTimeout(channel, data, timeout = 5000) {
return new Promise((resolve, reject) => {
const timeoutId = setTimeout(() => {
reject(new Error(`IPC调用超时: ${channel}`));
}, timeout);
window.electronAPI.invoke(channel, data)
.then(result => {
clearTimeout(timeoutId);
resolve(result);
})
.catch(error => {
clearTimeout(timeoutId);
reject(error);
});
});
}
// 监控 IPC 性能
monitorIPCPerformance() {
const originalInvoke = window.electronAPI.invoke;
window.electronAPI.invoke = async (channel, data) => {
const startTime = performance.now();
try {
const result = await originalInvoke(channel, data);
const duration = performance.now() - startTime;
// 记录性能数据
this.logIPCPerformance(channel, duration, true);
return result;
} catch (error) {
const duration = performance.now() - startTime;
this.logIPCPerformance(channel, duration, false);
throw error;
}
};
}
logIPCPerformance(channel, duration, success) {
if (duration > 100) { // 记录超过100ms的调用
console.warn(`⚠️ 慢IPC调用: ${channel}`, {
耗时: `${duration.toFixed(2)}ms`,
状态: success ? '成功' : '失败'
});
}
}
}
export const ipcOptimizer = new IPCOptimizer();
// 在主进程中实现批处理处理器
export function setupBatchHandler(ipcMain) {
ipcMain.handle('invoke-batch', async (event, channel, batchData) => {
const results = [];
for (const data of batchData) {
try {
// 这里需要根据实际IPC处理器来执行
const result = await processIPCBatch(channel, data);
results.push({ success: true, data: result });
} catch (error) {
results.push({ success: false, error: error.message });
}
}
return results;
});
}
async function processIPCBatch(channel, data) {
// 根据通道名称执行相应的处理逻辑
// 这里需要根据实际应用实现
switch (channel) {
case 'get-file-info':
return await getFileInfoBatch(data);
case 'query-data':
return await queryDataBatch(data);
default:
throw new Error(`未知的批处理通道: ${channel}`);
}
}构建与打包优化
生产环境构建优化
javascript
// webpack.config.js - Electron 生产构建配置
import { fileURLToPath } from 'url';
import { dirname, resolve } from 'path';
import webpack from 'webpack';
const __dirname = dirname(fileURLToPath(import.meta.url));
export default {
mode: 'production',
target: 'electron-renderer',
entry: {
main: './src/renderer/index.js',
preload: './src/preload/index.js'
},
output: {
path: resolve(__dirname, 'dist'),
filename: '[name].[contenthash].js',
chunkFilename: '[name].[contenthash].chunk.js',
clean: true
},
optimization: {
minimize: true,
minimizer: [
// 使用 Terser 进行代码压缩
new TerserPlugin({
parallel: true,
terserOptions: {
compress: {
drop_console: true, // 生产环境移除 console
drop_debugger: true
},
mangle: {
safari10: true
}
}
})
],
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
priority: 10
},
common: {
name: 'common',
minChunks: 2,
chunks: 'all',
priority: 5
}
}
},
runtimeChunk: {
name: 'runtime'
}
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
['@babel/preset-env', {
targets: {
electron: '22.0.0'
},
useBuiltIns: 'usage',
corejs: 3
}]
],
plugins: [
'@babel/plugin-syntax-dynamic-import',
'lodash' // 优化 lodash 引入
]
}
}
},
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: false,
sourceMap: false
}
}
]
}
]
},
plugins: [
// 定义环境变量
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production'),
'process.env.ELECTRON_IS_DEV': JSON.stringify(false)
}),
// 压缩 CSS
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css',
chunkFilename: '[name].[contenthash].chunk.css'
}),
// 分析包大小
new BundleAnalyzerPlugin({
analyzerMode: 'static',
openAnalyzer: false,
reportFilename: 'bundle-report.html'
})
],
resolve: {
alias: {
'@': resolve(__dirname, 'src'),
'components': resolve(__dirname, 'src/components')
},
extensions: ['.js', '.json']
},
// 排除 Electron 和 Node.js 内置模块
externals: {
electron: 'commonjs electron',
fs: 'commonjs fs',
path: 'commonjs path',
os: 'commonjs os'
}
};资源压缩与优化
javascript
// scripts/optimize-assets.js
import { promises as fs } from 'fs';
import { exec } from 'child_process';
import { promisify } from 'util';
import path from 'path';
const execAsync = promisify(exec);
export class AssetOptimizer {
constructor() {
this.imageExtensions = ['.png', '.jpg', '.jpeg', '.gif', '.svg'];
this.optimizedCount = 0;
}
async optimizeImages(sourceDir, targetDir) {
try {
const files = await fs.readdir(sourceDir);
for (const file of files) {
const filePath = path.join(sourceDir, file);
const stat = await fs.stat(filePath);
if (stat.isDirectory()) {
await this.optimizeImages(filePath, path.join(targetDir, file));
} else if (this.isImageFile(file)) {
await this.optimizeSingleImage(filePath, path.join(targetDir, file));
this.optimizedCount++;
}
}
console.log(`✅ 优化完成: ${this.optimizedCount} 个图片文件`);
} catch (error) {
console.error('❌ 资源优化失败:', error);
}
}
isImageFile(filename) {
const ext = path.extname(filename).toLowerCase();
return this.imageExtensions.includes(ext);
}
async optimizeSingleImage(sourcePath, targetPath) {
const ext = path.extname(sourcePath).toLowerCase();
// 确保目标目录存在
await fs.mkdir(path.dirname(targetPath), { recursive: true });
try {
switch (ext) {
case '.png':
// 使用 pngquant 优化 PNG
await execAsync(`pngquant --quality=65-80 --force --output "${targetPath}" "${sourcePath}"`);
break;
case '.jpg':
case '.jpeg':
// 使用 mozjpeg 优化 JPEG
await execAsync(`cjpeg -quality 80 -optimize -outfile "${targetPath}" "${sourcePath}"`);
break;
case '.svg':
// 使用 svgo 优化 SVG
await execAsync(`svgo "${sourcePath}" -o "${targetPath}"`);
break;
default:
// 直接复制不支持优化的文件
await fs.copyFile(sourcePath, targetPath);
}
} catch (error) {
// 如果优化工具不可用,直接复制文件
console.warn(`⚠️ 优化失败,直接复制: ${sourcePath}`);
await fs.copyFile(sourcePath, targetPath);
}
}
async createOptimizedBuild() {
const buildStartTime = Date.now();
console.log('🚀 开始优化构建...');
// 优化图片资源
await this.optimizeImages('src/assets', 'dist/assets');
// 复制其他资源
await this.copyOtherAssets('src/static', 'dist/static');
const buildTime = Date.now() - buildStartTime;
console.log(`🎉 构建完成,耗时: ${buildTime}ms`);
}
async copyOtherAssets(sourceDir, targetDir) {
try {
await fs.mkdir(targetDir, { recursive: true });
const files = await fs.readdir(sourceDir);
for (const file of files) {
const sourcePath = path.join(sourceDir, file);
const targetPath = path.join(targetDir, file);
const stat = await fs.stat(sourcePath);
if (stat.isDirectory()) {
await this.copyOtherAssets(sourcePath, targetPath);
} else if (!this.isImageFile(file)) {
await fs.copyFile(sourcePath, targetPath);
}
}
} catch (error) {
console.error('复制资源失败:', error);
}
}
}
// 执行优化
if (import.meta.url === `file://${process.argv[1]}`) {
const optimizer = new AssetOptimizer();
optimizer.createOptimizedBuild();
}监控与持续优化
性能监控系统
javascript
// src/utils/performance-monitor.js
export class PerformanceMonitor {
constructor() {
this.metrics = new Map();
this.reports = [];
this.monitoringEnabled = true;
}
startMonitoring() {
this.recordNavigationTiming();
this.recordResourceTiming();
this.recordPaintTiming();
this.startLongTaskMonitoring();
}
recordNavigationTiming() {
if (!performance.getEntriesByType) return;
const navigation = performance.getEntriesByType('navigation')[0];
if (navigation) {
this.metrics.set('navigation', {
domContentLoaded: navigation.domContentLoadedEventEnd - navigation.navigationStart,
loadComplete: navigation.loadEventEnd - navigation.navigationStart,
dnsLookup: navigation.domainLookupEnd - navigation.domainLookupStart,
tcpConnect: navigation.connectEnd - navigation.connectStart,
requestResponse: navigation.responseEnd - navigation.requestStart
});
}
}
recordResourceTiming() {
if (!performance.getEntriesByType) return;
const resources = performance.getEntriesByType('resource');
const resourceMetrics = resources.map(resource => ({
name: resource.name,
duration: resource.duration,
size: resource.transferSize || 0,
type: this.getResourceType(resource.name)
}));
this.metrics.set('resources', resourceMetrics);
}
recordPaintTiming() {
if (!performance.getEntriesByType) return;
const paints = performance.getEntriesByType('paint');
paints.forEach(paint => {
this.metrics.set(paint.name, paint.startTime);
});
}
startLongTaskMonitoring() {
if (!PerformanceObserver) return;
const observer = new PerformanceObserver((list) => {
list.getEntries().forEach(entry => {
if (entry.duration > 50) { // 超过50ms的任务
console.warn('⏱️ 长任务检测:', {
时长: `${entry.duration.toFixed(2)}ms`,
开始时间: entry.startTime
});
}
});
});
observer.observe({ entryTypes: ['longtask'] });
}
getResourceType(url) {
if (url.includes('.css')) return 'stylesheet';
if (url.includes('.js')) return 'script';
if (url.includes('.png') || url.includes('.jpg') || url.includes('.svg')) return 'image';
if (url.includes('.woff') || url.includes('.ttf')) return 'font';
return 'other';
}
generatePerformanceReport() {
const report = {
timestamp: new Date().toISOString(),
userAgent: navigator.userAgent,
connection: navigator.connection ? {
effectiveType: navigator.connection.effectiveType,
downlink: navigator.connection.downlink,
rtt: navigator.connection.rtt
} : null,
metrics: Object.fromEntries(this.metrics),
memory: performance.memory ? {
used: performance.memory.usedJSHeapSize,
total: performance.memory.totalJSHeapSize,
limit: performance.memory.jsHeapSizeLimit
} : null
};
this.reports.push(report);
return report;
}
// 获取性能评分
getPerformanceScore() {
const navigation = this.metrics.get('navigation');
if (!navigation) return null;
let score = 100;
// 基于加载时间的扣分
if (navigation.domContentLoaded > 3000) score -= 20;
else if (navigation.domContentLoaded > 2000) score -= 10;
if (navigation.loadComplete > 5000) score -= 20;
else if (navigation.loadComplete > 3000) score -= 10;
// 基于资源数量的扣分
const resources = this.metrics.get('resources') || [];
if (resources.length > 50) score -= 10;
else if (resources.length > 30) score -= 5;
return Math.max(0, score);
}
// 发送性能报告(可选)
async sendPerformanceReport() {
const report = this.generatePerformanceReport();
try {
// 在实际应用中,这里可以发送到性能监控服务
if (window.electronAPI) {
await window.electronAPI.sendPerformanceReport(report);
}
console.log('📊 性能报告已生成:', {
评分: this.getPerformanceScore(),
加载时间: report.metrics.navigation?.loadComplete
});
} catch (error) {
console.error('发送性能报告失败:', error);
}
}
}
export const performanceMonitor = new PerformanceMonitor();
// 自动开始监控
document.addEventListener('DOMContentLoaded', () => {
performanceMonitor.startMonitoring();
// 页面加载完成后发送初始报告
window.addEventListener('load', () => {
setTimeout(() => {
performanceMonitor.sendPerformanceReport();
}, 1000);
});
});