You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Abort Controller无法取消全部待处理请求,求排查问题原因

问题:部分Fetch请求无法被中止

我在项目中通过单个fetch函数处理所有请求,将所有Abort Controller存储在一个全局Set中。当用户切换到其他页面时,遍历该全局Set中止所有等待响应的fetch请求;当请求收到响应时,将对应的控制器从Set中移除。但目前仅部分请求能被取消,并非全部。

Fetch请求代码

const controller = new AbortController();
const request = { urlString, controller };
requests.activeRequests.add(request);
const signal = controller.signal;

fetch(urlString, {
    headers: headers,
    method: method,
    signal: signal,
    body: payload ? JSON.stringify(payload) : undefined,
    credentials: 'include' 
}).then(async (response) => {
    if (response.status === 200 || response.status === 204) {
        requests.activeRequests.delete(request);
        // 后续响应处理逻辑
    }
    // 未处理其他状态码的情况
})

页面切换时执行的代码

requests.activeRequests.forEach((req)=>{
    req.controller.abort();
    requests.activeRequests.delete(req)
})

问题原因

核心错误是在Set的forEach遍历过程中直接修改集合(调用delete)。Set的遍历机制依赖内部迭代器,当遍历过程中删除当前元素,会导致迭代器跳过下一个元素,从而部分请求的控制器从未被遍历到,也就不会被中止。

解决方案

方案1:将Set转为数组后遍历

遍历数组副本,修改原Set不会影响遍历流程:

Array.from(requests.activeRequests).forEach((req) => {
    req.controller.abort();
    requests.activeRequests.delete(req);
});

方案2:使用for...of循环遍历

for...of基于迭代器,但遍历过程中修改Set不会导致元素跳过:

for (const req of requests.activeRequests) {
    req.controller.abort();
    requests.activeRequests.delete(req);
}

额外优化:完善控制器移除逻辑

当前仅在响应状态为200/204时删除控制器,其他状态码(如400、500)或请求中止错误的情况下,控制器会残留于Set中。建议在finally块中统一移除,确保无论请求成功/失败/中止,都能清理控制器:

fetch(urlString, {
    // 配置项
})
.then(async (response) => {
    // 响应处理逻辑
})
.catch((err) => {
    // 错误处理,包括AbortError
})
.finally(() => {
    requests.activeRequests.delete(request);
});

内容的提问来源于stack exchange,提问作者AxelWolf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 06:22:23