引言:现代Web应用中的异步挑战
在当今复杂的前端应用中,高效处理大量异步操作已成为提升用户体验的关键。虽然Promise提供了基础的异步处理能力,但在实际项目中,我们经常需要处理成百上千个并发请求,如何优雅地控制并发数量、优化请求性能,是每个前端开发者必须掌握的技能。本文将深入探讨Promise的高级应用模式,并通过实际案例展示如何构建高性能的异步处理系统。
一、Promise并发控制的核心需求
1.1 为什么需要控制并发?
浏览器对同一域名的并发请求数有限制(通常为6个),超出限制的请求会被阻塞。对于需要处理大量异步操作的应用(如图片批量上传、大数据分页加载、多接口聚合等),无限制的并发会导致:
- 浏览器请求队列阻塞
- 服务器压力过大
- 客户端内存占用过高
- 用户体验下降(卡顿、延迟)
1.2 常见并发控制模式
// 顺序执行:一个完成后才开始下一个
async function sequential(tasks) {
const results = [];
for (const task of tasks) {
results.push(await task());
}
return results;
}
// 并行执行:所有任务同时开始
async function parallel(tasks) {
return Promise.all(tasks.map(task => task()));
}
// 控制并发数:同时最多执行n个任务
async function concurrent(tasks, maxConcurrent) {
// 实现细节将在下文展开
}
二、高性能并发控制器实现
2.1 基础并发控制实现
class PromisePool {
constructor(maxConcurrent = 5) {
this.maxConcurrent = maxConcurrent;
this.currentCount = 0;
this.queue = [];
this.results = [];
}
add(task) {
return new Promise((resolve, reject) => {
this.queue.push({
task,
resolve,
reject
});
this._next();
});
}
_next() {
while (this.currentCount {
resolve(result);
this.results.push({ status: 'fulfilled', value: result });
})
.catch(error => {
reject(error);
this.results.push({ status: 'rejected', reason: error });
})
.finally(() => {
this.currentCount--;
this._next();
});
}
}
async runAll(tasks) {
const promises = tasks.map(task => this.add(task));
await Promise.all(promises);
return this.results;
}
}
2.2 增强型并发控制器
class AdvancedPromisePool {
constructor(options = {}) {
const {
maxConcurrent = 5,
retryCount = 0,
timeout = 0,
onProgress = () => {}
} = options;
this.maxConcurrent = maxConcurrent;
this.retryCount = retryCount;
this.timeout = timeout;
this.onProgress = onProgress;
this.pending = new Set();
this.queue = [];
this.results = [];
this.completed = 0;
this.total = 0;
}
async add(task, priority = 0) {
return new Promise((resolve, reject) => {
this.queue.push({
task,
priority,
resolve,
reject,
retries: 0
});
this.total++;
this._next();
});
}
_executeTask(taskInfo) {
const { task, resolve, reject } = taskInfo;
const taskId = Symbol('taskId');
this.pending.add(taskId);
// 超时控制
const timeoutPromise = this.timeout > 0 ?
new Promise((_, timeoutReject) => {
setTimeout(() => timeoutReject(new Error('Task timeout')), this.timeout);
}) : null;
// 任务执行
const taskPromise = (async () => {
try {
return await task();
} catch (error) {
// 重试逻辑
if (taskInfo.retries {
resolve(result);
this.results.push({ status: 'fulfilled', value: result });
})
.catch(error => {
reject(error);
this.results.push({ status: 'rejected', reason: error });
})
.finally(() => {
this.pending.delete(taskId);
this.completed++;
this.onProgress({
completed: this.completed,
total: this.total,
pending: this.pending.size
});
this._next();
});
}
_next() {
// 按优先级排序
this.queue.sort((a, b) => b.priority - a.priority);
while (this.pending.size 0) {
const taskInfo = this.queue.shift();
this._executeTask(taskInfo);
}
}
async runAll(tasks, priorities = []) {
const promises = tasks.map((task, index) =>
this.add(task, priorities[index] || 0)
);
await Promise.all(promises);
return this.results;
}
clear() {
this.queue = [];
this.results = [];
this.completed = 0;
this.total = 0;
}
}
三、实战应用:图片批量上传组件
3.1 业务场景分析
用户需要一次性上传100张图片,要求:
- 同时最多上传5张图片
- 支持失败自动重试(最多3次)
- 单个上传超时时间为30秒
- 实时显示上传进度
- 支持优先级上传(重要图片优先)
3.2 实现代码
class BatchImageUploader {
constructor(options = {}) {
this.pool = new AdvancedPromisePool({
maxConcurrent: options.maxConcurrent || 5,
retryCount: options.retryCount || 3,
timeout: options.timeout || 30000,
onProgress: this._handleProgress.bind(this)
});
this.files = [];
this.onProgress = options.onProgress || (() => {});
this.onComplete = options.onComplete || (() => {});
this.onError = options.onError || (() => {});
}
addFiles(files) {
this.files = files;
}
setPriority(fileIndex, priority) {
// 设置文件上传优先级
this.priorities = this.priorities || {};
this.priorities[fileIndex] = priority;
}
async startUpload() {
const uploadTasks = this.files.map((file, index) =>
() => this._uploadSingleFile(file, index)
);
const priorities = this.files.map((_, index) =>
this.priorities ? this.priorities[index] || 0 : 0
);
try {
const results = await this.pool.runAll(uploadTasks, priorities);
this.onComplete(results);
} catch (error) {
this.onError(error);
}
}
async _uploadSingleFile(file, index) {
const formData = new FormData();
formData.append('file', file);
formData.append('index', index);
const response = await fetch('/api/upload', {
method: 'POST',
body: formData,
headers: {
'X-File-Name': encodeURIComponent(file.name),
'X-File-Size': file.size,
'X-File-Type': file.type
}
});
if (!response.ok) {
throw new Error(`Upload failed: ${response.status}`);
}
return response.json();
}
_handleProgress(progress) {
this.onProgress({
percent: Math.round((progress.completed / progress.total) * 100),
completed: progress.completed,
total: progress.total,
pending: progress.pending
});
}
cancel() {
this.pool.clear();
}
}
// 使用示例
const uploader = new BatchImageUploader({
maxConcurrent: 5,
retryCount: 3,
timeout: 30000,
onProgress: (progress) => {
console.log(`上传进度: ${progress.percent}%`);
},
onComplete: (results) => {
console.log('所有文件上传完成', results);
},
onError: (error) => {
console.error('上传出错', error);
}
});
// 添加文件并设置优先级
uploader.addFiles(fileList);
uploader.setPriority(0, 10); // 第一张图片高优先级
uploader.startUpload();
四、性能优化与内存管理
4.1 内存泄漏预防
class SafePromisePool extends AdvancedPromisePool {
constructor(options) {
super(options);
this._cleanupHandlers = new Set();
}
addCleanupHandler(handler) {
this._cleanupHandlers.add(handler);
}
async destroy() {
// 取消所有待执行任务
this.queue = [];
// 中止进行中的任务
for (const taskId of this.pending) {
this._abortTask(taskId);
}
// 执行清理操作
for (const handler of this._cleanupHandlers) {
try {
await handler();
} catch (error) {
console.warn('Cleanup handler error:', error);
}
}
this._cleanupHandlers.clear();
this.pending.clear();
}
_abortTask(taskId) {
// 实际项目中可能需要特定的中止逻辑
// 例如取消fetch请求、清除超时计时器等
if (taskId.abort) {
taskId.abort();
}
}
}
4.2 性能监控集成
class MonitoredPromisePool extends AdvancedPromisePool {
constructor(options) {
super(options);
this.metrics = {
startTime: 0,
totalTasks: 0,
succeeded: 0,
failed: 0,
retries: 0,
totalTime: 0
};
}
_executeTask(taskInfo) {
const startTime = performance.now();
return super._executeTask(taskInfo).finally(() => {
const duration = performance.now() - startTime;
this.metrics.totalTime += duration;
// 上报性能数据
this._reportMetrics({
taskDuration: duration,
taskStatus: taskInfo.status,
retryCount: taskInfo.retries
});
});
}
_reportMetrics(metric) {
// 实际项目中可集成到监控系统
console.debug('Task metric:', metric);
}
getPerformanceReport() {
return {
...this.metrics,
avgTime: this.metrics.totalTime / this.metrics.totalTasks,
successRate: this.metrics.succeeded / this.metrics.totalTasks
};
}
}
五、最佳实践与生产环境建议
5.1 配置建议
- 并发数设置:根据业务类型和设备能力动态调整(移动端建议2-3个)
- 超时时间:不同操作类型设置不同的超时策略
- 重试策略:指数退避重试,避免雪崩效应
- 内存管理:及时清理已完成的任务引用
5.2 错误处理策略
// 分级错误处理
const ERROR_STRATEGIES = {
NETWORK_ERROR: {
retry: true,
maxRetries: 3,
backoff: true
},
TIMEOUT: {
retry: true,
maxRetries: 2,
backoff: true
},
VALIDATION_ERROR: {
retry: false,
log: true
},
SERVER_ERROR: {
retry: true,
maxRetries: 1,
backoff: false
}
};
function getErrorStrategy(error) {
if (error.name === 'TimeoutError') {
return ERROR_STRATEGIES.TIMEOUT;
}
if (error.message.includes('network')) {
return ERROR_STRATEGIES.NETWORK_ERROR;
}
// ...其他错误类型判断
return ERROR_STRATEGIES.SERVER_ERROR;
}
结语:构建下一代异步应用架构
高效的Promise并发控制不仅是性能优化的关键技术,更是构建现代Web应用的基石。通过本文介绍的AdvancedPromisePool及其衍生模式,开发者可以轻松处理各种复杂的异步场景,从简单的批量操作到复杂的优先级调度系统。随着Web应用的日益复杂,良好的异步架构设计将成为区分优秀应用与普通应用的关键因素。建议在实际项目中根据具体需求灵活调整和扩展这些模式,构建最适合自己业务场景的异步处理解决方案。