如何优化 Promise 的性能?
Promise 的性能优化是提升应用响应速度和用户体验的关键。通过合理使用 Promise 和相关技术,可以显著提高异步操作的效率。避免不必要的 Promise 包装问题示例// 不推荐:不必要的 Promise 包装function fetchData() { return new Promise((resolve) => { resolve(fetch('/api/data')); });}// 推荐:直接返回 Promisefunction fetchData() { return fetch('/api/data');}优化原因不必要的 Promise 包装会增加额外的开销,包括:创建新的 Promise 对象额外的微任务调度增加内存占用并行执行独立操作顺序执行(慢)// 不推荐:顺序执行async function fetchAllData() { const user = await fetchUser(); const posts = await fetchPosts(); const comments = await fetchComments(); return { user, posts, comments };}并行执行(快)// 推荐:并行执行async function fetchAllData() { const [user, posts, comments] = await Promise.all([ fetchUser(), fetchPosts(), fetchComments() ]); return { user, posts, comments };}性能对比假设每个请求需要 100ms:顺序执行:300ms并行执行:100ms(3倍提升)避免过长的 Promise 链问题示例// 不推荐:过长的 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));}优化方案// 推荐:使用 async/awaitasync 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) );}合理使用缓存基本缓存实现const 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; });}带过期时间的缓存class 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()) );}请求去重基本去重实现const 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;}完整的去重实现class 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);});批量处理问题示例// 不推荐:逐个处理async function processItems(items) { const results = []; for (const item of items) { const result = await processItem(item); results.push(result); } return results;}优化方案// 推荐:批量处理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// 不推荐:过度使用 try/catchasync 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); }}优化方案// 推荐:合理的错误处理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; }}内存优化避免内存泄漏// 不推荐:可能导致内存泄漏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; }}优化方案// 推荐:使用 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 执行时间function 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' );}监控并发请求数class 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注意内存管理:避免内存泄漏监控性能指标:及时发现性能问题选择合适的并发数:根据实际情况调整并发策略