如何取消axios中的相同请求

在开发中,我们经常会遇到多个相同请求同时发送的情况。例如,在一个搜索功能中,用户可能会不断地输入关键字进行搜索,而每一次输入都会发送一个搜索请求。这种情况下,如果用户输入速度过快,可能会导致多个相同请求同时发送,而服务器返回的结果却可能不是用户最后一次输入的关键字所对应的结果。这就需要我们在发送新的请求时,同时取消上一个请求,以确保获取到正确的结果。

问题分析

为了解决上述问题,我们首先需要明确以下几点:

  1. 如何判断两个请求是否相同?
  2. 如何取消上一个请求?
  3. 如何避免取消请求时出现的问题?

接下来,我们将针对这三个问题进行解答,并给出相应的示例。

判断两个请求是否相同

在axios中,我们可以使用请求的cancelToken来取消请求。而每一个cancelToken都是由CancelToken工厂函数创建的。我们可以通过判断两个请求的cancelToken是否相同来判断这两个请求是否相同。

// 创建一个CancelToken
const source = axios.CancelToken.source();
const cancelToken = source.token;

// 发送请求时,将cancelToken传入config中
axios.get('/api/data', { cancelToken });

// 取消请求
source.cancel('Operation canceled by the user.');

取消上一个请求

要实现取消上一个请求,我们可以通过维护一个请求队列来达到目的。每当发送一个新的请求时,我们将上一个请求从队列中移除并取消。

let requestQueue = []; // 请求队列

function makeRequest() {
  // 取消上一个请求
  if (requestQueue.length > 0) {
    const { cancelTokenSource } = requestQueue.shift();
    cancelTokenSource.cancel('Operation canceled by the user.');
  }

  // 创建一个CancelToken
  const cancelTokenSource = axios.CancelToken.source();
  const cancelToken = cancelTokenSource.token;

  // 发送请求
  axios.get('/api/data', { cancelToken })
    .then((response) => {
      // 请求成功,处理返回的数据

      // 将当前请求添加到队列中
      requestQueue.push({ cancelTokenSource });
    })
    .catch((error) => {
      // 请求失败,处理错误信息

      // 将当前请求添加到队列中
      requestQueue.push({ cancelTokenSource });
    });
}

上述代码中,我们通过requestQueue数组来维护请求队列。在发送新的请求之前,我们首先会取消上一个请求,并将其从队列中移除。然后,我们创建一个新的cancelToken,并将其传入axios请求的config中。在请求成功或失败后,我们将当前请求添加到队列中,以备后续取消使用。

避免取消请求时出现的问题

在上述示例中,我们通过维护请求队列来取消上一个请求。然而,当用户输入速度过快时,可能会导致请求队列中的请求无法及时处理完毕,从而出现请求乱序或请求错误的问题。为了解决这个问题,我们可以使用debounce函数来限制发送请求的频率。

let requestQueue = []; // 请求队列
let debounceTimer = null; // 防抖计时器

function makeRequest() {
  // 取消上一个请求
  if (requestQueue.length > 0) {
    const { cancelTokenSource } = requestQueue.shift();
    cancelTokenSource.cancel('Operation canceled by the user.');
  }

  // 创建一个CancelToken
  const cancelTokenSource = axios.CancelToken.source();
  const cancelToken = cancelTokenSource.token;

  // 发送请求
  axios.get('/api/data', { cancelToken })
    .then((response) => {
      // 请求成功,处理返回的数据

      // 将当前请求添加到队列中
      requestQueue.push({ cancelTokenSource });
    })
    .catch((error) => {
      // 请求失败,处理错误信息

      // 将当前请求添加到队列中
      requestQueue.push({ cancelTokenSource });
    });
}

function debounceMakeRequest() {
  // 清除上一次的防抖计时器
  clearTimeout(debounceTimer);

  // 开启一个新的防抖计时器
  debounceTimer = setTimeout(() => {
    makeRequest();
  }, 500);