使用 abortcontroller 实例配合 fetch api 可以取消重复发起的相同请求。具体做法是在发起请求前检查是否存在正在进行的相同请求,如果存在则调用其 controller.abort() 方法中断旧请求,然后创建新的 controller 和请求;若不存在则保存该 controller 以便后续复用或取消。

如何识别并拦截重复的请求
通过维护一个全局映射表来存储当前正在进行的请求标识与对应的 AbortController。在发起新请求时,以请求 URL 和参数组合成的唯一键作为索引,查询该键是否已存在于映射表中。如果存在,说明有相同的请求正在进行中,此时直接获取旧的 controller 并执行 abort 操作,从而取消之前的请求。这种机制确保了同一时刻针对同一资源的请求只有一个处于活跃状态。

const pendingRequests = new Map();
function cancelDuplicateRequest(url, options = {}) {
const key = url;
if (pendingRequests.has(key)) {
const oldController = pendingRequests.get(key);
oldController.abort();
pendingRequests.delete(key);
}
}
async function fetchData(url, options = {}) {
cancelDuplicateRequest(url, options);
const controller = new AbortController();
const key = url;
pendingRequests.set(key, controller);
try {
const response = await fetch(url, { ...options, signal: controller.signal });
return await response.json();
} catch (error) {
if (error.name === 'AbortError') {
console.log('Request cancelled');
} else {
throw error;
}
} finally {
pendingRequests.delete(key);
}
}
如何处理请求完成后的清理工作
无论请求成功还是失败,都需要确保从 pendingRequests 映射表中移除对应的控制器引用,以防止内存泄漏。在 fetch 操作的 finally 块中执行删除操作是最稳妥的方式。这样即使请求被取消或发生错误,映射表也能保持干净,为下一次发起相同请求做好准备。同时,这也保证了当用户再次触发相同请求时,能够创建一个全新的 controller 而不是复用已废弃的对象。

async function safeFetch(url, options = {}) {
const key = url;
// 取消可能存在的重复请求
if (pendingRequests.has(key)) {
pendingRequests.get(key).abort();
}
const controller = new AbortController();
pendingRequests.set(key, controller);
try {
const response = await fetch(url, { ...options, signal: controller.signal });
return await response.json();
} catch (error) {
if (error.name !== 'AbortError') {
throw error;
}
} finally {
// 确保清理映射表
pendingRequests.delete(key);
}
}
基于信号状态判断请求是否被主动取消
当请求被取消时,fetch 会抛出一个名为 AbortError 的错误对象。开发者可以通过捕获这个特定类型的错误来区分网络异常和用户主动取消的行为。在实际应用中,可以根据业务逻辑决定是静默处理取消事件还是向用户展示提示。此外,controller.signal.aborted 属性可以在同步代码中直接检查请求是否已被标记为取消,无需等待异步结果返回。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











