序言

相信很多小伙伴都没有想过发出去的请求如何取消,一方面是普通的后台管理系统类型取消请求的需求不多,另外一方面是普通的后台管理系统涉及不到高并发的请求,以及连续的批量请求。

我在第一年的工作里,确实没有接触过取消请求的需求,对于这方面的知识也就没有积累,导致面试官问到如何取消请求时,我回答不上来,然后就是被一顿输出,最后不了了之。

正文

那么 axios 如何取消请求呢?本文介绍以下两种方式:
1、使用 axios 的静态方法

const CancelToken = axios.cancelToken
const source = CancelToken.source()

axios.get('/xxxx', {
   cancelToken: source.token
})

source.cancel('cancel request by user')

2、实例化 CancelToken

let cancel = null
axios.get('/xxxxx', {
  cancelToken: new CancelToken(function executor(c){
    cancel = c
  })
})

cancel()

封装一个好用的 hook 在项目里使用

import { onUnmounted, ref } from 'vue'
import type { CancelToken, CancelTokenSource } from 'axios'
import axios from 'axios'

/**
 * 封装一个可取消的 API 请求 hook
 * @param apiFn - 需要调用的 API 方法 (接收 cancelToken)
 */
export function useCancelableApi<T>(
  apiFn: (cancelToken: CancelToken) => Promise<T>,
) {
  const lastSource = ref<CancelTokenSource | null>(null)
  const loading = ref(false)
  const error = ref<unknow>()

  function abort() {
    if (lastSource.value) {
      lastSource.value.cancel('Request aborted')
      lastSource.value = null
    }
  }

  async function fetchData(): Promise<T> {
    abort() // 先取消上一次
    lastSource.value = axios.CancelToken.source()
    loading.value = true
    error.value = undefined

    try {
      const res = await apiFn(lastSource.value.token)
      return res
    }
    catch (err: unknown) {
      error.value = err 
      throw err
    }
    finally {
      loading.value = false
    }
  }

  onUnmounted(() => {
    abort()
  })

  return {
    fetchData,
    abort,
    loading,
    error,
  }
}

使用方式

const getData = async (cancelToken: CancelToken) => {
  return await apiGetData(query, cancelToken)
}

const { fetchData, abort } = useCancelableApi(getDealsData)

// 使用 fetchData 获取数据 使用 abort 可以取消请求