欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

axios之cancelToken取消多次重复请求 有大用 有大大用

一、我们为什么需要取消?

我们常见的业务场景有,用户频繁点击数据提交,用户频繁的切换数据量大的表格,在网络较差的环境下,会出现一些异常的情况,当然,各类UI库提供的loading状态可以帮我们解决以上烦恼,以及可以通过防抖解决部分问题,但是我们今天从另一个方面,使用axios的cancelToken取消上次重复的请求。

二、我们怎样取消?

先看一下aixos官方文档的cancelToken的代码

方法1:可以使用 CancelToken.source 工厂方法创建 cancel token,像这样:

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

axios.get('/user/12345', {
  cancelToken: source.token
}).catch(function(thrown) {
  if (axios.isCancel(thrown)) {
    console.log('Request canceled', thrown.message);
  } else {
     // 处理错误
  }
});

axios.post('/user/12345', {
  name: 'new name'
}, {
  cancelToken: source.token
})

// 取消请求(message 参数是可选的)
source.cancel('Operation canceled by the user.');

方法2:还可以通过传递一个 executor 函数到 CancelToken 的构造函数来创建 cancel token:

const CancelToken = axios.CancelToken;
let cancel;

axios.get('/user/12345', {
  cancelToken: new CancelToken(function executor(c) {
    // executor 函数接收一个 cancel 函数作为参数
    cancel = c;
  })
});

// cancel the request
cancel();

如何在我们项目中使用呢?

我们项目中,更常用的做法是在拦截器interceptors中使用。

当然,我们需要先定义一个map对象用于存储相关值(map为es6新增对象,如果你对es6不了解,请查阅阮一峰的ECMAScript 6 入门

// 用于存储pending的请求(处理多条相同请求)
const pendingRequest = new Map()

其次,需要封装一些辅助类的函数

  • generateRequestKey 将重复的请求生成一个唯一的key

import qs from 'qs'
// 生成request的唯一key
const generateRequestKey = (config = {}) => {
  // 通过url,method,params,data生成唯一key,用于判断是否重复请求
  // params为get请求参数,data为post请求参数
  const { url, method, params, data } = config
  return [url, method, qs.stringify(params), qs.stringify(data)].join('&')
}
  • addPendingRequest将重复的请求,保存到到pendingRequest

// addPendingRequest 将重复请求添加到pendingRequest中
const addPendingRequest = (config) => {
  const key = generateRequestKey(config)
  if (!pendingRequest.has(key)) { //判断pendingRequest中是否存在key
    config.cancelToken = new axios.CancelToken(cancel => {
      pendingRequest.set(key, cancel) //将key和cancel以键值对的方式保存
    })
  }
}
  • 将重复的请求取消,并在pendingRequest中删除

// removePendingRequest 取消重复请求
const removePendingRequest = (config) => {
  const key = generateRequestKey(config)
  if (pendingRequest.has(key)) { //判断pendingRequest中是否存在key
    const cancelToken = pendingRequest.get(key)
    cancelToken(key) // 取消之前发送的请求
    pendingRequest.delete(key)// 请求对象中删除requestKey
  }
}

完整代码

import axios from 'axios'
import qs from 'qs'

// 用于存储pending的请求(处理多条相同请求)
const pendingRequest = new Map()

// 生成request的唯一key
const generateRequestKey = (config = {}) => {
  // 通过url,method,params,data生成唯一key,用于判断是否重复请求
  // params为get请求参数,data为post请求参数
  const { url, method, params, data } = config
  return [url, method, qs.stringify(params), qs.stringify(data)].join('&')
}

// 将重复请求添加到pendingRequest中
const addPendingRequest = (config) => {
  const key = generateRequestKey(config)
  if (!pendingRequest.has(key)) {
    config.cancelToken = new axios.CancelToken(cancel => {
      pendingRequest.set(key, cancel)
    })
  }
}

// 取消重复请求
const removePendingRequest = (config) => {
  const key = generateRequestKey(config)
  if (pendingRequest.has(key)) {
    const cancelToken = pendingRequest.get(key)
    cancelToken(key) // 取消之前发送的请求
    pendingRequest.delete(key)// 请求对象中删除requestKey
  }
}

// 请求拦截器
service.interceptors.request.use(
  config => {
    // 处理重复请求
    removePendingRequest(config)
    addPendingRequest(config)

    return config
  },
  error => {
    // 处理请求错误
    return Promise.reject(error)
  }
)

// 响应拦截器
service.interceptors.response.use(
  response => {
    // 移除重复请求
    removePendingRequest(response.config)
    
    return res
  },
  error => {
    // 异常情况console,方便排查问题
    console.log('error', error)
    // 移除重复请求
    removePendingRequest(error.config || {})
    
    return Promise.reject(error)
  }
)

三、结尾

代码中如有需要更正和修改的地方,欢迎评论留言,我也会积极回复。

分类:前端标签:JavaScriptaxios安装掘金浏览器插件多内容聚合浏览、多引擎快捷搜索、多工具便捷提效、多模式随心畅享,你想要的,这里都有!前往安装

评论全部评论 4最新最热永恒万花筒的头像删除永恒万花筒这两种方法的区别是什么呢,是第二种手动封装了官方提供的source的方法吗点赞3删除EasyEDA_Developer lv-1CancelToken() 构造函数的返回值是一个 token 实例,它的参数是一个 execute 函数,该函数的形参是一个cancel函数,这个cancel函数就是 source 对象的 cancel 函数,只不过在 axios 内部把 source 对象的 cancel 函数作为参数传递给了 execute 函数作为参数,
我们在 execute 函数内部获取到了 cancel 函数,就可以在我们需要的地方调用它,然后终止请求3回复删除永恒万花筒回复EasyEDA_Developer强,理解了“CancelToken() 构造函数的返回值是一个 token 实例,它的参数是一个 execute 函数,该函数的形参是一个cancel函数,这个cancel函数就是 source 对象的 cancel 函数,只不过在 axios 内部把 source 对象的 cancel 函数作为参数传递给了 execute 函数作为参数,
我们在 execute 函数内部获取到了 cancel 函数,就可以在我们需要的地方调用它,然后终止请求”点赞回复删除杨小在 lv-1(作者)回复EasyEDA_Developer<img draggable="false" "="" loading="lazy" alt="[赞]" src="//lf3-cdn-tos.bytescm.com/obj/static/xitu_juejin_web/img/jj_emoji_108.a6defc6.png">“CancelToken() 构造函数的返回值是一个 token 实例,它的参数是一个 execute 函数,该函数的形参是一个cancel函数,这个cancel函数就是 source 对象的 cancel 函数,只不过在 axios 内部把 source 对象的 cancel 函数作为参数传递给了 execute 函数作为参数,
我们在 execute 函数内部获取到了 cancel 函数,就可以在我们需要的地方调用它,然后终止请求”点赞回复84收藏相关推荐
作者:杨小在
链接:https://juejin.cn/post/7025884912141991972
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。



来自  https://juejin.cn/post/7025884912141991972

普通分类: