Promise.allSettled用于安全并行执行,等待所有Promise完成并返回状态对象;AsyncLimiter类实现限流控制,支持动态调整并发数与暂停/恢复功能。

并发控制:用 Promise.allSettled 实现安全的并行执行
当需要同时发起多个异步请求,又不希望一个失败导致整体中断时,Promise.allSettled 是比 Promise.all 更稳妥的选择。它会等待所有 Promise 完成(无论 fulfilled 或 rejected),返回每个结果的状态对象。
例如批量获取用户信息:
async function fetchUsersConcurrently(ids) {
const promises = ids.map(id =>
fetch(`/api/users/${id}`)
.then(res => res.json())
.catch(err => ({ error: err.message }))
);
const results = await Promise.allSettled(promises);
return results.map((r, i) => ({
id: ids[i],
data: r.status === 'fulfilled' ? r.value : null,
error: r.status === 'rejected' ? r.reason : null
}));
}限流控制:手写 async 队列管理器(无第三方依赖)
限制同一时间最多执行 N 个异步任务,可封装一个轻量级 AsyncLimiter 类。核心是维护运行中任务数 + 任务队列,用 Promise 链式调度。
- 构造时指定最大并发数 max
- add(fn) 接收一个返回 Promise 的函数,返回包装后的 Promise
- 内部通过 running 计数和 queue 缓存待执行任务
示例实现:
立即学习“Java免费学习笔记(深入)”;
在调试 Java 后端 API 故障时使用此技能,尤其适用于以下任务:分析日志、跨 Controller、Service 和 Mapper 层追踪请求、定位异常根因、检查 SQL 执行或参数流转,以及生成简洁的诊断结论与修复方案。
class AsyncLimiter {
constructor(max) {
this.max = max;
this.running = 0;
this.queue = [];
}
add(fn) {
return new Promise((resolve, reject) => {
this.queue.push({ fn, resolve, reject });
this.#run();
});
}
async #run() {
if (this.running >= this.max || this.queue.length === 0) return;
this.running++;
const { fn, resolve, reject } = this.queue.shift();
try {
const result = await fn();
resolve(result);
} catch (err) {
reject(err);
} finally {
this.running--;
this.#run(); // 尝试启动下一个
}
}
}
<p>// 使用示例:限制最多 3 个并发 fetch
const limiter = new AsyncLimiter(3);
const requests = urls.map(url => () => fetch(url).then(r => r.json()));
const results = await Promise.all(requests.map(req => limiter.add(req)));优雅组合:async/await + 限流器 + 错误恢复
真实场景中常需“限流 + 失败重试 + 超时控制”。可在限流器基础上增强,或在调用层叠加逻辑。推荐分层处理:
- 底层用 AsyncLimiter 控制并发
- 每个任务内用 try/catch + setTimeout 实现指数退避重试
- 用 AbortController 统一控制单个请求超时
例如带重试的请求封装:
async function fetchWithRetry(url, options = {}, retries = 3) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000);
<p>for (let i = 0; i <= retries; i++) {
try {
const res = await fetch(url, { ...options, signal: controller.signal });
clearTimeout(timeoutId);
return res;
} catch (err) {
if (i === retries) throw err;
await new Promise(r => setTimeout(r, Math.pow(2, i) * 100)); // 指数退避
}
}
}进阶技巧:动态调整并发数与暂停/恢复支持
某些场景下需运行时修改限流阈值(如根据系统负载自动降级),或临时暂停任务队列。可在 AsyncLimiter 中扩展方法:
- setMax(n):更新 this.max 并触发一次 #run()
- pause():设 this.paused = true,#run() 开头检查该标志
- resume():设 this.paused = false 并立即调用 #run()
这样既保持接口简洁,又具备生产环境所需的弹性能力。不复杂但容易忽略。

















