乐闻世界logo
搜索文章和话题

如何优化 Promise 的性能?

2月22日 14:07

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) ); }

合理使用缓存

基本缓存实现

javascript
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; }); }

带过期时间的缓存

javascript
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()) ); }

请求去重

基本去重实现

javascript
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; }

完整的去重实现

javascript
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); });

批量处理

问题示例

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 执行时间

javascript
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' ); }

监控并发请求数

javascript
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)); }

总结

  1. 避免不必要的 Promise 包装:减少额外的开销
  2. 并行执行独立操作:利用 Promise.all 提高性能
  3. 避免过长的 Promise 链:使用 async/await 提高可读性
  4. 合理使用缓存:减少重复请求
  5. 实现请求去重:避免重复的网络请求
  6. 批量处理数据:提高处理效率
  7. 优化错误处理:避免过度嵌套的 try/catch
  8. 注意内存管理:避免内存泄漏
  9. 监控性能指标:及时发现性能问题
  10. 选择合适的并发数:根据实际情况调整并发策略
标签:Promise