javascript 中实现请求取消的重试机制,核心在于利用 abortcontroller 实例化一个信号对象,并将其传递给 fetch 或 xmlhttprequest。当需要重试时,调用该控制器的 abort() 方法中断当前请求,随后在捕获到因中止引发的异常后,重新发起新的请求并绑定一个新的控制器实例。

如何在中途主动中断正在进行的网络请求
通过创建 AbortController 对象并获取其 signal 属性,可以在发起请求时将其作为配置项传入。一旦调用控制器的 abort() 方法,浏览器会立即终止该请求,并在 Promise 链中抛出一个名为 AbortError 的 DOMException 对象。

const controller = new AbortController();
const signal = controller.signal;
// 发起请求
fetch('https://api.example.com/data', { signal })
.then(response => response.json())
.catch(error => {
if (error.name === 'AbortError') {
console.log('请求已被手动取消');
} else {
console.error('其他错误:', error);
}
});
// 随时可以触发取消
controller.abort();上述代码展示了最基础的取消流程。关键在于 signal 对象的传递,它建立了请求与控制器之间的关联。当 abort() 被调用时,关联的请求状态会变为中止,从而阻止后续的数据处理逻辑执行。
立即学习“Java免费学习笔记(深入)”;
如何在捕获取消异常后自动重新发起请求
要实现重试,需要在 catch 块中判断错误类型是否为 AbortError。如果是,则说明是预期的取消操作,此时可以再次调用 fetch 发起新请求。为了避免无限重试,通常需要引入计数器或最大重试次数限制。

async function fetchWithRetry(url, maxRetries = 3) {
let retries = 0;
while (retries <= maxRetries) {
const controller = new AbortController();
try {
const response = await fetch(url, { signal: controller.signal });
return await response.json();
} catch (error) {
if (error.name === 'AbortError') {
// 如果是主动取消,直接退出循环
break;
}
// 如果是网络错误且还有重试机会
if (retries < maxRetries) {
retries++;
continue; // 继续下一次循环,发起新请求
}
throw error; // 超过重试次数,抛出最终错误
}
}
}在这个示例中,每次循环都会创建一个新的 AbortController。这样确保即使前一次请求被取消,也不会影响下一次请求的信号状态。如果请求成功,函数直接返回结果;如果失败且未达上限,则增加重试计数并继续循环。
基于特定输入条件触发的取消与重试行为
在实际应用中,往往需要根据特定的业务条件来决定是否取消并重试。例如,当用户快速切换页面或点击取消按钮时,应取消当前请求以避免资源浪费和状态混乱。此时,可以将 AbortController 实例挂载到组件或全局状态中,以便在外部触发取消事件。
let currentController = null;
function fetchData(inputId) {
// 如果有正在进行的请求,先取消它
if (currentController) {
currentController.abort();
}
// 创建新的控制器
currentController = new AbortController();
const { signal } = currentController;
fetch(`/api/data?id=${inputId}`, { signal })
.then(res => res.json())
.then(data => {
console.log('获取到数据:', data);
currentController = null; // 请求完成,清理引用
})
.catch(err => {
if (err.name !== 'AbortError') {
console.error('请求失败:', err);
}
});
}
// 模拟用户输入变化
fetchData(1);
setTimeout(() => fetchData(2), 500); // 500ms后改变输入,触发取消并重试这段代码演示了基于输入变化的取消重试逻辑。当 fetchData 被再次调用时,它会先检查是否存在旧的控制器实例。如果存在,则调用 abort() 取消旧请求,然后创建新的控制器发起新请求。这种模式有效防止了竞态条件,确保只有最新的请求结果会被处理。


















