axios取消前一次请求

236 阅读1分钟

背景

项目中有一个内容区域和tab栏,选中不同的tab选项展示对应的内容,如果内容由后端返回,前端发起两次请求,如果第二次请求先返回,则会先展示第二次请求的内容,最后展示第一次请求的内容。而用户期望的是最终展示最后一次选择的结果。因此,当发起第二次请求前,需要取消上一次请求。

复现步骤:

  1. 请求tab2的内容,3秒后返回
  2. 请求tab3的内容,立即返回
  3. 内容区域显示顺序: tab3的内容 -> tab2的内容 iShot_2023-10-23_20.33.58.gif

前端代码 github代码

  1. axios请求文件 src/util/request.ts
import axios from "axios";

const http = axios.create({
  baseURL: "http://localhost:3000",
  timeout: 5000,
});

// 获取tab内容
export const getTabContent = (index: number) => {
  return http.get(`/tab/${index}`);
};

  1. 页面 src/App.vue
<template>
  <div class="container">
    <div class="btns">
      <button  v-for="i in 3" :key="i" @click="handleTabClick(i)" >{{ `tab${i}` }}</button>
    </div>
    <div class="context">{{ context }}</div>
  </div>
</template>

<script setup lang="ts">
import { handleError, ref } from 'vue'
import { getTabContent } from '@/utils/request'

const context = ref('tab1的内容...')

const handleTabClick = async (index:number) => {
  const { data } = await getTabContent(index)
  context.value = data
}
 
</script>

后端代码 github代码

// app.ts
const express = require("express");
const app = express();

const cors = require("cors");
app.use(cors());

app.get("/tab/:id", (req, res) => {
  if (req.params.id === "1") {
    setTimeout(() => {
      res.send("这是tab1的内容...");
    }, 1000);
  } else if (req.params.id === "2") {
    setTimeout(() => {
      res.send("这是tab2的内容...");
    }, 3000);
  } else if (req.params.id === "3") {
    res.send("这是tab3的内容...");
  }
});

app.listen("3000", () => {
  console.log("server running at 3000 port...");
});

解决办法

AbortController

最新axios官方文档推荐的方法 文档地址 简而言之,new一个AbortController对象,将其signal属性作为参数传递给axios的请求方法中

  1. 优化后的request.ts
import axios from "axios";

const http = axios.create({
  baseURL: "http://localhost:3000",
  timeout: 5000,
});

let controller: any;

export const getTabContent = (index: number) => {
  // 取消上一次请求
  if (controller) {
    controller.abort();
  } 
  // 发起新的请求
  controller = new AbortController();
  return http.get(`/tab/${index}`, { signal: controller.signal });
};

最终效果

前一次请求被cancel,最终显示tab3的内容 iShot_2023-10-24_09.44.08.gif