异步数据去重队列是通过map缓存promise实现请求去重,或用set+队列实现事件流有序去重,结合防抖与abortcontroller优化高频操作。

JavaScript 数组去重本身是同步操作,但“异步数据的去重队列”实际指的是:在异步数据(如 API 请求、定时任务、事件流)持续到达时,按顺序处理并自动过滤重复项,同时保证不丢失、不乱序、不阻塞后续请求。这不是单纯调用 Set 或 filter,而是构建一个带状态管理的异步处理管道。
用 Map + Promise 缓存实现去重请求队列
适用于重复请求同一 ID/参数的场景(如多次点击加载用户详情)。核心思路是:相同参数的请求只发一次,后续请求复用首次返回的 Promise。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 用 Map 存储「请求标识 → 正在进行的 Promise」映射
- 每次请求前先查 Map,命中则直接返回缓存 Promise;未命中则发起新请求,并把 Promise 存入 Map
- 请求完成后(无论成功/失败),从 Map 中删除该键,避免内存泄漏
class DedupedRequestQueue {
constructor() {
this.cache = new Map();
}
async request(key, fetcher) {
if (this.cache.has(key)) {
return this.cache.get(key);
}
const promise = fetcher().finally(() => this.cache.delete(key));
this.cache.set(key, promise);
return promise;
}
}
// 使用
const queue = new DedupedRequestQueue();
queue.request('user_123', () => fetch('/api/user/123').then(r => r.json()));
queue.request('user_123', () => fetch('/api/user/123').then(r => r.json())); // 复用上一个 Promise
用队列 + Set 实现有序去重消费流
适用于异步事件或数据流(如 WebSocket 消息、按钮点击事件)不断推送 item,需按接收顺序处理且跳过重复项。
- 维护一个 Set 记录已处理过的唯一标识(如 id、hash)
- 用数组或 Queue 类 缓存待处理项,确保 FIFO(先进先出)
- 消费时检查是否已存在,不存在才处理并加入 Set
class DedupedQueue {
constructor() {
this.seen = new Set();
this.queue = [];
}
push(item, keyFn = x => x.id) {
const key = keyFn(item);
if (!this.seen.has(key)) {
this.seen.add(key);
this.queue.push(item);
}
}
async process(handler) {
while (this.queue.length > 0) {
const item = this.queue.shift();
await handler(item);
}
}
}
// 使用:模拟异步事件流入
const dq = new DedupedQueue();
dq.push({ id: 1, name: 'Alice' });
dq.push({ id: 1, name: 'Alice (dup)' }); // 被忽略
dq.push({ id: 2, name: 'Bob' });
dq.process(item => console.log('处理:', item.name)); // 输出 Alice, Bob
结合 async/await 与防抖/节流控制高频重复提交
当用户快速多次触发同一操作(如搜索框输入),需去重+限频,避免无效并发请求。
- 对输入值做 防抖(debounce),等待用户停止输入再发起请求
- 请求前用当前关键词生成唯一 key,配合上述 Map 缓存策略避免重复请求
- 可选:添加 abortController,在新请求发出时中止旧请求
let pending = null;
async function search(query) {
const key = `search_${query}`;
if (pending && pending.key === key) return pending.promise;
// 取消上一个未完成请求(可选)
if (pending?.abort) pending.abort();
const abort = new AbortController();
const promise = fetch(`/api/search?q=${query}`, { signal: abort.signal })
.then(r => r.json())
.finally(() => { pending = null; });
pending = { key, promise, abort };
return promise;
}
注意事项与边界处理
- 内存泄漏:长期运行的 Map/Set 需定期清理(如设置 TTL、最大容量或使用 WeakMap/WeakSet 仅限对象引用)
- 深比较需求:若 key 不是简单类型(如对象参数),需序列化(JSON.stringify)或自定义 hash 函数,注意循环引用和函数不可序列化问题
-
错误隔离:单个请求失败不应影响其他请求,Promise 缓存中建议用
.catch(() => {})或明确 reject 后清除缓存 - 服务端去重更可靠:前端去重只是体验优化,关键业务逻辑(如下单)必须由服务端幂等接口保障
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










