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
相关产品推荐
相关产品推荐

