性能优化 #

一、性能概述 #

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