🧱 多次请求时如何取消之前的接口请求

0 阅读5分钟

为什么在多次请求时需要取消之前的接口请求?以及如何在路由切换时取消未完成的请求?

在前端开发中,特别是在处理异步数据请求(如通过 Axios 发送 HTTP 请求)时,我们常常会遇到 用户快速连续触发相同或相关接口请求 的场景。如果不加控制地让这些请求同时进行,可能会导致一些不必要的问题,比如:

  • 数据混乱(例如分页加载时后一个请求先返回,覆盖了前一个正确的结果);
  • 不必要的网络开销和资源浪费;
  • 用户体验差(如页面显示错乱、加载状态异常等)。

为了解决这些问题,通常我们会选择 取消上一次未完成的请求,确保只有最新的请求会真正影响到应用的状态与 UI 显示。


🧩 常见使用场景

场景一:搜索框输入自动补全

当用户在搜索框中输入内容时,前端会根据输入内容发送请求获取匹配的结果(如联想词、商品建议等)。如果用户连续快速输入(如 a -> ab -> abc),每个输入都会触发一次请求,但旧的请求可能已经没有意义了。此时应该取消之前所有未完成的请求,只保留最后一次请求的响应。

场景二:分页加载数据

在表格组件中,点击不同页码会请求对应的数据。如果用户快速点击多个页码(如从第一页跳到第五页),中间的请求可能已经不再需要,继续接收它们的响应会导致错误的数据被渲染到当前页面。

场景三:实时更新的图表数据

某个图表每隔几秒刷新一次数据,但如果用户切换了时间范围或筛选条件,那么旧的定时任务中的请求就应当被取消,避免旧数据污染新的视图。


🔁 如何实现请求取消?以 Axios 为例

Axios 提供了 CancelToken API 来取消请求。在 Vue 或 React 中,我们可以通过封装请求服务来统一管理请求取消逻辑。

示例代码(简化版):

ts
深色版本
import axios from 'axios'

const service = axios.create({
  baseURL: '/api',
  timeout: 5000,
})

let cancelTokenSource = axios.CancelToken.source()

service.interceptors.request.use(config => {
  config.cancelToken = cancelTokenSource.token
  return config
})

// 每次发起新请求前调用这个方法取消上一次请求
export function cancelAllRequests() {
  cancelTokenSource.cancel('Operation canceled by the user.')
  cancelTokenSource = axios.CancelToken.source()
}

export default service

这样,每次发出新请求前调用 cancelAllRequests() 方法,即可取消掉上一次尚未完成的请求。


🚪 在路由切换时取消请求

在 Vue 应用中,当用户导航到其他页面时,可能还有一些未完成的请求正在进行。为了避免这些请求在离开页面后仍然尝试更新已卸载组件的状态或 DOM,我们应该在路由切换时主动取消这些请求。

使用 router.afterEach 实现:

ts
深色版本
import { router } from '@/router'
import { cancelAllRequests } from '@/utils/request'

router.afterEach((to, from) => {
  cancelAllRequests()
  // 这里还可以执行一些不影响导航的清理操作
})

✅ 这样做的好处是:

  • 防止在离开页面后接收到响应数据时尝试更新已卸载的组件,从而避免潜在的内存泄漏或报错;
  • 提升用户体验,避免页面切换后出现“旧数据短暂闪现”等问题。

✅ 这么做的好处有哪些?

好处描述
提升用户体验确保最终呈现给用户的是最新且正确的数据,避免因异步请求顺序不确定造成的界面混乱。
减少服务器压力取消无用请求可以降低后端服务器的负载,节省带宽和计算资源。
避免数据污染在使用 Vuex/Pinia/Redux 等状态管理工具时,防止过期数据污染状态树。
增强程序健壮性减少因为异步回调顺序不确定而产生的 bug,提高代码可维护性和稳定性。

📌 实际案例说明

假设你有一个分页表格组件,用户点击页码 1 → 2 → 3,但第 1 页的请求响应最慢,第 3 页反而先回来并更新了表格,之后第 1 页又回来了,这时候如果不取消之前的请求,它会把当前显示的第 3 页数据替换为第 1 页的,造成数据错乱。

使用 CancelToken 后,第 1 和第 2 页的请求会被取消,只有第 3 页的请求成功返回,正确更新表格数据。

此外,如果用户在加载第 2 页数据的过程中跳转到了详情页,我们通过 router.afterEach 取消请求,可以避免在详情页中接收到第 2 页的响应并尝试更新已被销毁的组件。


💡 总结

在现代 Web 开发中,合理使用请求取消机制是构建高性能、高稳定性的应用的重要手段之一。它不仅有助于提升用户体验,还能优化前后端之间的交互效率。

通过 Axios 的 CancelToken 或更现代的 AbortController(Fetch API)机制,我们可以轻松实现对请求生命周期的精细控制,从而避免“异步请求竞争”带来的各种副作用。

结合 Vue Router 的 afterEach 生命周期钩子,我们可以在页面切换时及时取消未完成的请求,避免数据污染和潜在的内存泄漏问题。


📄 扩展建议

  • 如果你使用的是 Pinia/Vuex,可以将 CancelToken 的实例统一管理在 store 中,方便模块化控制。
  • 对于复杂的业务场景,也可以按需实现“部分请求取消”而非全局取消。
  • 在移动端或低网速环境下,这类优化尤其重要。