Promise 的性能优化是提升应用响应速度和用户体验的关键。通过合理使用 Promise 和相关技术,可以显著提高异步操作的效率。
避免不必要的 Promise 包装
问题示例
javascript// 不推荐:不必要的 Promise 包装 function fetchData() { return new Promise((resolve) => { resolve(fetch('/api/data')); }); } // 推荐:直接返回 Promise function fetchData() { return fetch('/api/data'); }
优化原因
不必要的 Promise 包装会增加额外的开销,包括:
- 创建新的 Promise 对象
- 额外的微任务调度
- 增加内存占用
并行执行独立操作
顺序执行(慢)
javascript// 不推荐:顺序执行 async function fetchAllData() { const user = await fetchUser(); const posts = await fetchPosts(); const comments = await fetchComments(); return { user, posts, comments }; }
并行执行(快)
javascript// 推荐:并行执行 async function fetchAllData() { const [user, posts, comments] = await Promise.all([ fetchUser(), fetchPosts(), fetchComments() ]); return { user, posts, comments }; }
性能对比
假设每个请求需要 100ms:
- 顺序执行:300ms
- 并行执行:100ms(3倍提升)
避免过长的 Promise 链
问题示例
javascript// 不推荐:过长的 Promise 链 function processLargeData(data) { return Promise.resolve(data) .then(data => processData1(data)) .then(data => processData2(data)) .then(data => processData3(data)) .then(data => processData4(data)) .then(data => processData5(data)) .then(data => processData6(data)) .then(data => processData7(data)) .then(data => processData8(data)); }
优化方案
javascript// 推荐:使用 async/await async function processLargeData(data) { data = await processData1(data); data = await processData2(data); data = await processData3(data); data = await processData4(data); data = await processData5(data); data = await processData6(data); data = await processData7(data); data = await processData8(data); return data; } // 或者:使用函数组合 function processLargeData(data) { return [processData1, processData2, processData3, processData4, processData5, processData6, processData7, processData8] .reduce((promise, processor) => promise.then(processor), Promise.resolve(data) ); }
合理使用缓存
基本缓存实现
javascriptconst cache = new Map(); function fetchWithCache(url) { if (cache.has(url)) { return Promise.resolve(cache.get(url)); } return fetch(url) .then(response => response.json()) .then(data => { cache.set(url, data); return data; }); }
带过期时间的缓存
javascriptclass PromiseCache { constructor(ttl = 60000) { this.cache = new Map(); this.ttl = ttl; } get(key) { const item = this.cache.get(key); if (!item) return null; if (Date.now() > item.expiry) { this.cache.delete(key); return null; } return item.value; } set(key, value) { this.cache.set(key, { value, expiry: Date.now() + this.ttl }); } async fetch(key, fetcher) { const cached = this.get(key); if (cached) return cached; const value = await fetcher(); this.set(key, value); return value; } } // 使用示例 const cache = new PromiseCache(60000); async function fetchUser(id) { return cache.fetch(`user:${id}`, () => fetch(`/api/users/${id}`).then(r => r.json()) ); }
请求去重
基本去重实现
javascriptconst pendingRequests = new Map(); function fetchDeduplicated(url) { if (pendingRequests.has(url)) { return pendingRequests.get(url); } const promise = fetch(url) .then(response => response.json()) .finally(() => { pendingRequests.delete(url); }); pendingRequests.set(url, promise); return promise; }
完整的去重实现
javascriptclass RequestDeduplicator { constructor() { this.pendingRequests = new Map(); } async fetch(url, options = {}) { const key = this.getRequestKey(url, options); if (this.pendingRequests.has(key)) { return this.pendingRequests.get(key); } const promise = fetch(url, options) .then(response => { if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); }) .finally(() => { this.pendingRequests.delete(key); }); this.pendingRequests.set(key, promise); return promise; } getRequestKey(url, options) { return JSON.stringify({ url, options }); } } // 使用示例 const deduplicator = new RequestDeduplicator(); // 多次调用同一个 URL,只会发起一次请求 Promise.all([ deduplicator.fetch('/api/user'), deduplicator.fetch('/api/user'), deduplicator.fetch('/api/user') ]).then(results => { console.log('所有请求返回相同结果:', results); });
批量处理
问题示例
javascript// 不推荐:逐个处理 async function processItems(items) { const results = []; for (const item of items) { const result = await processItem(item); results.push(result); } return results; }
优化方案
javascript// 推荐:批量处理 async function processItems(items, batchSize = 10) { const results = []; for (let i = 0; i < items.length; i += batchSize) { const batch = items.slice(i, i + batchSize); const batchResults = await Promise.all( batch.map(item => processItem(item)) ); results.push(...batchResults); } return results; }
错误处理优化
避免过度使用 try/catch
javascript// 不推荐:过度使用 try/catch async function fetchData() { try { try { const response = await fetch('/api/data'); try { const data = await response.json(); try { const processed = await processData(data); return processed; } catch (error) { console.error('处理失败:', error); } } catch (error) { console.error('解析失败:', error); } } catch (error) { console.error('请求失败:', error); } } catch (error) { console.error('未知错误:', error); } }
优化方案
javascript// 推荐:合理的错误处理 async function fetchData() { try { const response = await fetch('/api/data'); const data = await response.json(); return await processData(data); } catch (error) { if (error instanceof NetworkError) { console.error('网络错误:', error.message); } else if (error instanceof ParseError) { console.error('解析错误:', error.message); } else { console.error('未知错误:', error); } throw error; } }
内存优化
避免内存泄漏
javascript// 不推荐:可能导致内存泄漏 class DataFetcher { constructor() { this.cache = new Map(); } async fetch(url) { if (this.cache.has(url)) { return this.cache.get(url); } const data = await fetch(url).then(r => r.json()); this.cache.set(url, data); return data; } }
优化方案
javascript// 推荐:使用 WeakMap 或限制缓存大小 class DataFetcher { constructor(maxSize = 100) { this.cache = new Map(); this.maxSize = maxSize; } async fetch(url) { if (this.cache.has(url)) { return this.cache.get(url); } const data = await fetch(url).then(r => r.json()); // 限制缓存大小 if (this.cache.size >= this.maxSize) { const firstKey = this.cache.keys().next().value; this.cache.delete(firstKey); } this.cache.set(url, data); return data; } }
性能监控
监控 Promise 执行时间
javascriptfunction withPerformanceTracking(promise, label) { const startTime = performance.now(); return promise .then(result => { const duration = performance.now() - startTime; console.log(`${label} 完成,耗时: ${duration.toFixed(2)}ms`); return result; }) .catch(error => { const duration = performance.now() - startTime; console.error(`${label} 失败,耗时: ${duration.toFixed(2)}ms`, error); throw error; }); } // 使用示例 async function fetchData() { return withPerformanceTracking( fetch('/api/data').then(r => r.json()), 'fetchData' ); }
监控并发请求数
javascriptclass RequestMonitor { constructor() { this.activeRequests = 0; this.maxConcurrentRequests = 0; } async monitor(promise) { this.activeRequests++; this.maxConcurrentRequests = Math.max( this.activeRequests, this.maxConcurrentRequests ); try { return await promise; } finally { this.activeRequests--; } } getStats() { return { activeRequests: this.activeRequests, maxConcurrentRequests: this.maxConcurrentRequests }; } } // 使用示例 const monitor = new RequestMonitor(); async function fetchWithMonitor(url) { return monitor.monitor(fetch(url)); }
总结
- 避免不必要的 Promise 包装:减少额外的开销
- 并行执行独立操作:利用 Promise.all 提高性能
- 避免过长的 Promise 链:使用 async/await 提高可读性
- 合理使用缓存:减少重复请求
- 实现请求去重:避免重复的网络请求
- 批量处理数据:提高处理效率
- 优化错误处理:避免过度嵌套的 try/catch
- 注意内存管理:避免内存泄漏
- 监控性能指标:及时发现性能问题
- 选择合适的并发数:根据实际情况调整并发策略