Vue 3 中实现请求取消的核心是 AbortController 配合 onUnmounted 自动清理,封装为 useRequestCancel 组合式函数,支持自动取消、手动 abort 和 isAborted 状态响应式控制,TypeScript 类型安全且兼容 fetch/axios。

在 Vue 3 中实现请求取消,核心是利用 AbortController(现代浏览器原生支持)配合 onUnmounted 清理,再用 TypeScript 类型安全地封装成可复用的组合式函数(Composable)。关键不是“取消状态”,而是“可取消的请求能力”——取消本身是动作,状态只是辅助判断(如 isAborted 或 isPending)。
✅ 封装 useRequestCancel 钩子(推荐基础版)
这个钩子返回一个 controller 实例和一个 abort 方法,并自动在组件卸载时调用 abort():
import { onUnmounted } from 'vue';
export function useRequestCancel() {
const controller = new AbortController();
const abort = () => {
if (!controller.signal.aborted) {
controller.abort();
}
};
onUnmounted(abort);
return {
controller,
abort,
};
}
使用示例:
import { ref, onMounted } from 'vue';
import { useRequestCancel } from './useRequestCancel';
export function useUserData() {
const data = ref<any>(null);
const loading = ref(false);
const error = ref<error null>(null);
const { controller } = useRequestCancel();
const fetchUser = async (id: string) => {
loading.value = true;
try {
const res = await fetch(`/api/users/${id}`, {
signal: controller.signal, // ? 关键:传入 signal
});
data.value = await res.json();
} catch (err) {
if (err instanceof DOMException && err.name === 'AbortError') {
// 请求被取消,通常不视为业务错误
console.log('Request aborted');
} else {
error.value = err as Error;
}
} finally {
loading.value = false;
}
};
return { data, loading, error, fetchUser };
}</error></any>
✅ 增强版:带 isAborted 状态与手动控制
如果确实需要显式暴露取消状态(例如 UI 显示“已取消”或禁用重试按钮),可扩展返回值:
将静态 Vue 页面(index.vue)改造为动态页面(Custom.vue);稿源仅限 index.vue、其引用的 CSS 与资源路径,禁止参考仓库内其他文件。Invoke when user wants to transform a static Vue page into a dynamic data-driven page with Element UI components.
import { onUnmounted, ref } from 'vue';
export function useRequestCancel(autoAbortOnUnmount = true) {
const controller = new AbortController();
const isAborted = ref(controller.signal.aborted);
const abort = () => {
if (!controller.signal.aborted) {
controller.abort();
isAborted.value = true;
}
};
if (autoAbortOnUnmount) {
onUnmounted(abort);
}
return {
controller,
abort,
isAborted,
};
}
此时可在模板中响应式使用 isAborted.value 控制 UI:
<button :disabled="loading || isAborted">加载用户</button> <span v-if="isAborted">⚠️ 请求已被取消</span>
✅ 注意事项与 TypeScript 类型要点
-
AbortSignal 类型已内置:TypeScript 4.9+ 自带
AbortSignal和AbortController类型,无需额外安装类型包 -
捕获 AbortError 要精确:用
err instanceof DOMException && err.name === 'AbortError'判断,避免误判网络错误 -
不要重复创建 controller:每个请求应有独立 controller;若需多次请求,应在每次调用前新建(或在钩子内提供
newController()方法) -
axios 用户注意:v1.0+ 支持
signal,直接传入即可;旧版需用cancelToken(已废弃,不推荐)
✅ 可选:集成进 useAsync 或 useFetch(类比 VueUse)
若项目已用 @vueuse/core,可直接用 useFetch,它原生支持 signal 和自动清理:
import { useFetch } from '@vueuse/core';
const { data, isFetching, execute, abort } = useFetch('/api/users/1', {
immediate: false,
// ✅ 内置 signal 支持,abort() 即触发取消
});
// 手动取消
abort();
// 组件卸载时自动 abort(useFetch 默认启用)
其 TypeScript 类型完整,返回值含 abort: () => void 和 isFinished: Ref 等,开箱即用。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










