Electron applications consume significant system resources by default due to the integration of Chromium and Node.js. Through reasonable optimization strategies, you can significantly improve application performance and user experience.
Reducing Application Size
1. Exclude Unnecessary Files
json// package.json { "build": { "files": [ "build/**/*", "node_modules/**/*", "package.json" ], "asar": true, "asarUnpack": [ "node_modules/some-native-module/**/*" ] } }
2. Use Production Dependencies
bash# Development environment npm install --save-dev electron electron-builder # Production environment - only install necessary dependencies npm install --production
3. Compress Resources
json{ "build": { "compression": "maximum", "files": [ "!**/node_modules/*/{TEST,test,tests,__tests__,examples,example}/**", "!**/node_modules/.bin", "!**/*.{iml,o,hprof,orig,pyc,pyo,rbc,swp,csproj,sln,xproj}", "!.editorconfig", "!**/._*", "!**/{.DS_Store,.git,.hg,.svn,CVS,RCS,SCCS,.gitignore,.gitattributes}", "!**/{__pycache__,thumbs.db,.flowconfig,.idea,.vs,.nyc_output}", "!**/{appveyor.yml,.travis.yml,circle.yml}", "!**/{npm-debug.log,yarn.lock,.yarn-integrity,.yarn-metadata.json}" ] } }
Memory Optimization
1. Lazy Load Modules
javascript// Bad practice - Load all modules at the top const heavyModule = require('heavy-module') function useHeavyModule() { heavyModule.doSomething() } // Good practice - Load on demand function useHeavyModule() { const heavyModule = require('heavy-module') heavyModule.doSomething() }
2. Use Dynamic Import
javascript// Renderer process async function loadFeature() { const { feature } = await import('./heavy-feature.js') feature.init() }
3. Clean Up Unused Objects
javascript// Clean up event listeners in time function setupListeners() { const handler = () => console.log('Event') window.addEventListener('resize', handler) // Clean up when component unmounts return () => window.removeEventListener('resize', handler) } // Usage const cleanup = setupListeners() // When no longer needed cleanup()
4. Limit Cache Size
javascript// Use LRU cache const LRU = require('lru-cache') const cache = new LRU({ max: 500, // Maximum number of cache items maxAge: 1000 * 60 * 5 // Expire after 5 minutes }) function getData(key) { const cached = cache.get(key) if (cached) return cached const data = fetchData(key) cache.set(key, data) return data }
Rendering Performance Optimization
1. Use Virtual Lists
javascript// Use react-window or react-virtualized import { FixedSizeList as List } from 'react-window' const Row = ({ index, style }) => ( <div style={style}>Row {index}</div> ) const VirtualList = () => ( <List height={600} itemCount={10000} itemSize={35} width={300} > {Row} </List> )
2. Avoid Frequent DOM Operations
javascript// Bad practice for (let i = 0; i < 1000; i++) { document.body.appendChild(createElement(i)) } // Good practice - Use document fragment const fragment = document.createDocumentFragment() for (let i = 0; i < 1000; i++) { fragment.appendChild(createElement(i)) } document.body.appendChild(fragment)
3. Use requestAnimationFrame
javascript// Bad practice function animate() { element.style.left = position + 'px' position += 1 setTimeout(animate, 16) } // Good practice function animate() { element.style.left = position + 'px' position += 1 requestAnimationFrame(animate) }
4. Optimize Image Loading
javascript// Use lazy loading const img = new Image() img.loading = 'lazy' img.src = 'image.jpg' // Use WebP format const supportsWebP = document.createElement('canvas') .toDataURL('image/webp') .indexOf('data:image/webp') === 0 const imageFormat = supportsWebP ? 'webp' : 'jpg' img.src = `image.${imageFormat}`
Process Optimization
1. Share Resources When Using Multiple Windows
javascript// main.js const sharedSession = session.defaultSession const window1 = new BrowserWindow({ webPreferences: { session: sharedSession } }) const window2 = new BrowserWindow({ webPreferences: { session: sharedSession } })
2. Use Worker Threads for Intensive Tasks
javascript// main.js const { Worker } = require('worker_threads') ipcMain.handle('heavy-computation', async (event, data) => { return new Promise((resolve, reject) => { const worker = new Worker('./worker.js', { workerData: data }) worker.on('message', resolve) worker.on('error', reject) worker.on('exit', (code) => { if (code !== 0) reject(new Error(`Worker stopped with exit code ${code}`)) }) }) }) // worker.js const { parentPort, workerData } = require('worker_threads') const result = performHeavyComputation(workerData) parentPort.postMessage(result)
3. Use Child Processes for Independent Tasks
javascript// main.js const { spawn } = require('child_process') function runTask(data) { return new Promise((resolve, reject) => { const child = spawn('node', ['task.js', JSON.stringify(data)]) let output = '' child.stdout.on('data', (data) => { output += data.toString() }) child.on('close', (code) => { if (code === 0) { resolve(JSON.parse(output)) } else { reject(new Error(`Process exited with code ${code}`)) } }) }) }
Network Optimization
1. Use Service Worker Caching
javascript// sw.js self.addEventListener('install', (event) => { event.waitUntil( caches.open('v1').then((cache) => { return cache.addAll([ '/', '/styles/main.css', '/scripts/main.js' ]) }) ) }) self.addEventListener('fetch', (event) => { event.respondWith( caches.match(event.request).then((response) => { return response || fetch(event.request) }) ) })
2. Use HTTP/2
javascript// main.js app.on('ready', () => { session.defaultSession.webRequest.onBeforeSendHeaders((details, callback) => { details.requestHeaders['Upgrade-Insecure-Requests'] = '1' callback({ requestHeaders: details.requestHeaders }) }) })
3. Optimize API Requests
javascript// Use request batching const batchRequests = [] function scheduleRequest(request) { batchRequests.push(request) if (batchRequests.length >= 10) { flushRequests() } } function flushRequests() { const requests = batchRequests.splice(0, batchRequests.length) ipcRenderer.invoke('batch-request', requests) } // Periodic flush setInterval(flushRequests, 100)
Startup Optimization
1. Lazy Load Non-Critical Resources
javascript// main.js app.whenReady().then(() => { const mainWindow = new BrowserWindow({ show: false // Don't show initially }) mainWindow.loadFile('index.html') // Show after page loads mainWindow.once('ready-to-show', () => { mainWindow.show() }) })
2. Preload Common Data
javascript// preload.js const { contextBridge, ipcRenderer } = require('electron') contextBridge.exposeInMainWorld('electronAPI', { getInitialData: () => ipcRenderer.invoke('get-initial-data') }) // renderer.js window.addEventListener('DOMContentLoaded', async () => { const initialData = await window.electronAPI.getInitialData() // Use initial data })
3. Use Code Splitting
javascript// Use dynamic import for code splitting async function loadFeature() { const { default: Feature } = await import('./features/feature.js') new Feature() }
Monitoring and Debugging
1. Use Chrome DevTools
javascript// main.js const mainWindow = new BrowserWindow({ webPreferences: { devTools: true } }) // Auto-open DevTools in development if (process.env.NODE_ENV === 'development') { mainWindow.webContents.openDevTools() }
2. Performance Profiling
javascript// main.js mainWindow.webContents.on('did-finish-load', () => { mainWindow.webContents.executeJavaScript(` const observer = new PerformanceObserver((list) => { for (const entry of list.getEntries()) { console.log(entry.name, entry.duration) } }) observer.observe({ entryTypes: ['measure'] }) `) })
3. Memory Monitoring
javascript// main.js setInterval(() => { const memoryUsage = process.memoryUsage() console.log('Memory Usage:', { rss: `${Math.round(memoryUsage.rss / 1024 / 1024)} MB`, heapTotal: `${Math.round(memoryUsage.heapTotal / 1024 / 1024)} MB`, heapUsed: `${Math.round(memoryUsage.heapUsed / 1024 / 1024)} MB`, external: `${Math.round(memoryUsage.external / 1024 / 1024)} MB` }) }, 30000)
Best Practices Summary
- Reduce Application Size: Exclude unnecessary files, use production dependencies, compress resources
- Memory Optimization: Lazy loading, timely cleanup, limit cache
- Rendering Optimization: Virtual lists, reduce DOM operations, use RAF
- Process Optimization: Share resources, use Worker Threads
- Network Optimization: Service Worker, HTTP/2, request batching
- Startup Optimization: Lazy loading, preload data, code splitting
- Monitoring and Debugging: DevTools, performance profiling, memory monitoring
Common Questions
Q: What to do if Electron application uses too much memory?A: Check for memory leaks, use lazy loading, limit cache size, clean up unused objects in time.
Q: How to improve application startup speed?A: Lazy load non-critical resources, preload common data, use code splitting, optimize initialization logic.
Q: How to implement virtual lists?A: Use libraries like react-window or react-virtualized to only render elements within the visible area.
Q: How to detect memory leaks?A: Use Chrome DevTools Memory panel, regularly monitor memory usage, check if event listeners and timers are properly cleaned up.