通过装饰器模式实现请求取消的核心思路是拦截原请求函数,注入 abortcontroller 实例并绑定 abortsignal,在触发取消逻辑时调用 signal.abort()。具体做法是创建一个高阶函数,接收原始 fetch 或 axios 请求函数作为参数,返回一个增强后的函数,该函数接受额外的配置项用于控制取消行为。当需要取消请求时,只需调用 abort() 方法即可中断正在进行的网络请求,从而避免资源浪费和状态不一致。

如何封装通用的请求取消装饰器
封装通用装饰器的关键在于将 AbortController 的生命周期与请求绑定。我们定义一个 withAbort 函数,它接收一个目标请求函数(如 fetch),并返回一个新的函数。新函数在执行实际请求前创建 AbortController,并将 signal 传递给底层请求。同时,返回的对象包含一个 abort 方法,供外部调用以触发取消。这种设计确保了取消逻辑与业务逻辑解耦,且支持多次复用。

function withAbort(requestFn) {
return function(url, options = {}) {
const controller = new AbortController();
const signal = controller.signal;
// 合并用户传入的 signal,如果用户已提供则优先使用
if (options.signal) {
signal.addEventListener('abort', () => controller.abort());
}
const wrappedOptions = { ...options, signal };
const promise = requestFn(url, wrappedOptions);
// 返回增强后的 Promise 对象,附带 abort 方法
return Object.assign(promise, {
abort: () => controller.abort(),
signal: signal
});
};
}
上述代码展示了基于原生 fetch 的装饰器实现。调用 withAbort(fetch) 后得到的新函数,其返回值是一个标准的 Promise,但额外挂载了 abort 属性。开发者可以直接调用 req.abort() 来中断请求。若用户在 options 中传入了自己的 signal,装饰器会监听该信号并在触发时同步调用内部控制器,确保多源取消信号的一致性。此实现不依赖任何第三方库,适用于所有支持 AbortSignal 的环境。
立即学习“Java免费学习笔记(深入)”;
如何处理取消异常与重试逻辑
请求被取消时会抛出 AbortError,这属于正常流程而非错误,因此在装饰器外层需进行区分处理。结合重试机制时,只有非取消类的异常才应触发重试。我们在装饰器返回的 Promise 链中添加 catch 块,判断错误类型是否为 DOMException 且名称为 AbortError。若是,则直接拒绝或返回特定状态;否则,进入重试逻辑。这样既保证了取消的即时性,又避免了因网络抖动导致的无效重试。

async function retryableRequest(url, retries = 3) {
const request = withAbort(fetch);
let lastError;
for (let i = 0; i <= retries; i++) {
try {
const response = await request(url);
if (!response.ok) throw new Error('HTTP error');
return await response.json();
} catch (error) {
if (error.name === 'AbortError') {
console.log('Request aborted by user');
throw error; // 取消不应重试
}
lastError = error;
if (i === retries) break;
await new Promise(r => setTimeout(r, 1000 * Math.pow(2, i)));
}
}
throw lastError;
}
// 使用示例
const req = retryableRequest('/api/data');
setTimeout(() => req.abort(), 5000); // 5秒后取消
该示例展示了如何将取消装饰器与重试逻辑结合。retryableRequest 函数内部使用 withAbort(fetch) 发起请求。在循环中,每次请求失败都会检查错误类型。如果捕获到 AbortError,说明是主动取消,此时立即抛出异常终止重试,符合预期行为。对于其他网络错误,则等待指数退避时间后重试。最后,通过 setTimeout 模拟外部取消操作,验证了装饰器在复杂场景下的有效性。这种模式确保了取消操作的优先级高于重试,提升了用户体验。
当 AbortSignal 触发时装饰器内部状态如何变化
当 AbortSignal 触发时,浏览器会自动中止挂起的网络请求,并立即向 Promise 链抛出一个 AbortError。在装饰器内部,AbortController 的 abort() 方法被调用后,其关联的 signal 的 aborted 属性变为 true。此时,任何监听该信号的回调都会执行,但不会改变 Promise 的最终状态,而是通过异常传播机制通知调用者。装饰器本身不捕获此异常,而是将其透传给上层,由调用者决定是忽略、记录还是重新发起请求。这种设计保持了装饰器的纯粹性,仅负责注入能力,而不干预业务流。


















