013-Promise.all-race-allSettled概念+手撕

Promise 并发控制方法详解

一、核心静态方法概念

方法 描述 特性 结果
Promise.all(iterable) 等待所有 Promise 成功 短路特性(一个失败立即拒绝) 成功:结果数组
失败:第一个错误
Promise.race(iterable) 采用第一个完成的 Promise 竞速机制 第一个落定的结果(无论成功/失败)
Promise.allSettled(iterable) 等待所有 Promise 完成 不短路,收集所有结果 状态描述对象数组

二、手写实现

1. 手写 Promise.all
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Promise.myAll = function(promises) {
return new Promise((resolve, reject) => {
const results = [];
let completed = 0;

promises.forEach((promise, i) => {
Promise.resolve(promise)
.then(value => {
results[i] = value;
if (++completed === promises.length) resolve(results);
})
.catch(reject); // 任一失败立即拒绝
});
});
};
2. 手写 Promise.race
1
2
3
4
5
6
7
8
9
Promise.myRace = function(promises) {
return new Promise((resolve, reject) => {
promises.forEach(promise => {
Promise.resolve(promise)
.then(resolve)
.catch(reject);
});
});
};
3. 手写 Promise.allSettled
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Promise.myAllSettled = function(promises) {
return new Promise(resolve => {
const results = [];
let completed = 0;

const checkCompletion = () => {
if (++completed === promises.length) resolve(results);
};

promises.forEach((promise, i) => {
Promise.resolve(promise)
.then(value => {
results[i] = { status: 'fulfilled', value };
})
.catch(reason => {
results[i] = { status: 'rejected', reason };
})
.finally(checkCompletion);
});
});
};

三、使用 Promise 实现请求并发控制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class RequestPool {
constructor(maxConcurrent) {
this.max = maxConcurrent; // 最大并发数
this.queue = []; // 等待队列
this.running = 0; // 当前运行数
}

// 添加请求到池中
add(requestFn) {
return new Promise((resolve, reject) => {
const task = () => {
this.running++;
requestFn()
.then(resolve)
.catch(reject)
.finally(() => {
this.running--;
this.next();
});
};

// 立即执行或加入队列
if (this.running < this.max) {
task();
} else {
this.queue.push(task);
}
});
}

// 执行下一个任务
next() {
if (this.queue.length > 0 && this.running < this.max) {
const task = this.queue.shift();
task();
}
}
}
使用示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 1. 创建并发池(最大3个)
const pool = new RequestPool(3);

// 2. 模拟异步请求函数
const createRequest = (id, delay) => () =>
new Promise(resolve =>
setTimeout(() => resolve(`请求${id}完成`), delay)
);

// 3. 添加10个请求
for (let i = 1; i <= 10; i++) {
pool.add(createRequest(i, Math.random() * 2000))
.then(console.log); // 按完成顺序输出
}

/* 输出特点:
1. 同时最多3个请求并行
2. 完成一个立即补位下一个
3. 最终按实际完成顺序输出结果 */

四、关键实现原理

  1. 并发控制核心逻辑

    • 任务队列:存储等待执行的任务
    • 运行计数器:跟踪当前执行中的任务数
    • 自动补位机制:任务完成时自动触发下一个任务
  2. Promise 方法实现要点

    • 正确处理非 Promise 值(Promise.resolve()包装)
    • 保持结果顺序(数组索引定位)
    • 短路处理(all的立即拒绝)

五、实际应用场景

场景 推荐方法 说明
批量表单提交 Promise.all 需要全部成功,任一失败终止
竞速请求 Promise.race 获取最快响应(如CDN检测)
批量数据采集 Promise.allSettled 需要完整结果(无论成败)
图片懒加载 并发控制 避免同时加载过多图片
API 分页请求 并发控制 控制分页请求并发数量

六、特殊处理技巧

  1. 错误重试机制
1
pool.add(() => fetch(url).catch(() => fetch(url))) // 失败自动重试
  1. 优先级队列
1
2
3
4
5
// 高优先级任务
pool.queue.unshift(highPriorityTask);

// 低优先级任务
pool.queue.push(lowPriorityTask);
  1. 超时控制
1
2
3
4
5
6
pool.add(() => 
Promise.race([
fetch(url),
new Promise((_, r) => setTimeout(() => r('超时'), 5000))
])
);

性能提示:浏览器通常有 6-8 个 TCP 连接限制,合理设置并发数可优化性能