Vue 3 中无法使用 Vue.prototype 创建全局事件总线,应采用 mitt 实现事件驱动式请求取消:每个请求新建 AbortController 并订阅 'cancel-all' 事件,在路由跳转、输入中断或组件卸载时统一触发取消。

Vue 3 中无法直接使用 Vue.prototype 创建全局事件总线,所以不能像 Vue 2 那样把 `$bus` 挂载到原型上。但你可以用 mitt 搭配 AbortController 或 CancelToken,实现“通过事件统一触发取消”的机制——本质是:在关键时机(如路由跳转、输入中断、组件卸载)发布一个“取消所有请求”事件,各请求监听该事件并主动 abort。
为什么不用全局总线直接管理 cancel 函数?
因为 Vue 3 不再支持全局原型挂载,且集中维护所有 pending 请求的 cancel 句柄容易泄漏或误删。更健壮的做法是:每个请求自己创建控制器,再订阅一个通用的取消信号。
用 mitt 实现“事件驱动式请求取消”
步骤清晰,不依赖全局变量:
- 安装 mitt:npm install mitt
- 创建事件总线实例(推荐单例):
src/utils/bus.jsimport mitt from 'mitt';<br>export const bus = mitt();
- 在请求封装层(如 src/api/request.js)中自动绑定 signal:
```js
import axios from 'axios';
import { bus } from '@/utils/bus';
// 创建 axios 实例
const request = axios.create({ baseURL: '/api' });
// 请求拦截器:为每个请求注入 abort signal
request.interceptors.request.use(config => {
const controller = new AbortController();
config.signal = controller.signal;
// 订阅全局取消事件,触发时 abort 当前请求
const off = bus.on('cancel-all', () => controller.abort());
// 将 off 存入 config,便于响应后清理
config.__cleanup = () => off();
return config;
});
// 响应拦截器:清理订阅
request.interceptors.response.use(
response => {
response.config?.__cleanup?.();
return response;
},
error => {
if (error.name === 'AbortError' || axios.isCancel(error)) {
console.log('请求已被事件总线取消');
return Promise.reject(new Error('canceled-by-bus'));
}
response.config?.__cleanup?.();
return Promise.reject(error);
}
);
export default request;
```
立即学习“前端免费学习笔记(深入)”;
在哪里触发“取消全部”?
按需发布事件即可,例如:
-
路由切换时(src/router/index.js):
router.beforeEach((to, from, next) => {<br> bus.emit('cancel-all');<br> next();<br>}); -
搜索框防抖中断时:
watch(searchTerm, (val) => {<br> bus.emit('cancel-all'); // 先取消旧请求<br> if (val) fetchData(val);<br>}); - 组件卸载前(可选补充)**:
onBeforeUnmount(() => {<br> bus.emit('cancel-all');<br>});
注意点和边界情况
• AbortController 的 signal 是一次性使用的,abort 后不可重用;每次请求都新建是安全做法。
• mitt 的 on 是弱引用监听,无需手动 off —— 除非你长期保留某个监听(比如在 setup 中反复注册),否则不会内存泄漏。
• 不建议用 mitt 传递具体 URL 或 ID 去“精准取消某请求”,那会增加复杂度;统一取消 + 后端幂等/前端防抖才是更简洁可靠的组合策略。
• 如果项目仍在用 axios v0.21.x 及以下,可用 CancelToken 替代 AbortController,逻辑类似,只是写法稍异。


















