< 今日小技巧:Axios封装,接口请求增加防抖功能 >

简介: 今天这篇文章,主要是讲述对axios封装的请求,由于部分请求可能存在延时的情况。使得接口可能存在会被持续点击(即:接口未响应的时间内,被持续请求),导致重复请求的问题,容易降低前后端服务的性能!故提出给axios封装的配置里面,新增一个防抖函数,用来限制全局请求的防抖。

image.png


👉 前言

防抖节流概念: < 性能优化:认识防抖与节流,如何实现呢?它们又有何区别? >

今天这篇文章,主要是讲述对axios封装的请求,由于部分请求可能存在延时的情况。使得接口可能存在会被持续点击(即:接口未响应的时间内,被持续请求),导致重复请求的问题,容易降低前后端服务的性能!

故提出给axios封装的配置里面,新增一个防抖函数,用来限制全局请求的防抖。不过介于部分接口可能存在需要持续请求的情况,所以增加一个参数来判断是否启用防抖函数

👉 一、核心代码 : 防抖函数

const debounce = (fn, delay, immediate = true) => {
  // 1.定义一个定时器, 保存上一次的定时器

  let timeout = JSON.parse(localStorage.getItem('timeout')) || null
  // window.console.log(fn, delay, timeout)
  // 2.真正执行的函数
  const _debounce = function() {
    let context = this;
    let args = arguments;

    if (timeout) clearTimeout(timeout); // timeout 不为null
    if (immediate) {
      // 第一次会立即执行,以后只有事件执行后才会再次触发
      let callNow = !timeout;
      timeout = setTimeout(function() {
        timeout = null;
      }, delay)
      if (callNow) {
        fn.apply(context, args)
      }
    } else {
      timeout = setTimeout(function() {
        fn.apply(context, args)
      }, delay);
    }
    localStorage.setItem('timeout', timeout)
  }

  // 封装取消功能
  _debounce.cancel = function() {
    if (timeout) clearTimeout(timeout)
    timeout = null
    localStorage.setItem('timeout', null)
  }

  return _debounce
}

export default debounce;

👉 二、Axios封装中的配置

// 使用axios请求
this.xxxName({
  ...
  isDebounce: true // 入参
})
  .then((res) => {
    ...
  })
  .finally(() => {});

---------------------------------------------------

import debounce from "./debounce.js";

export default function(options) {
  // options 为接口入参配置,options.data为接口参数
  ...
  let isDebounce = false;
  
  try{
    isDebounce = config.data.isDebounce;
    if(isDebounce) {
      delete data.isDebounce;
    }
  } catch(e){
    //TODO handle the exception
    isDebounce = false
  }
  
  return createPromise(type, url, data, config, socket, cache, isDebounce);
}

function createPromise(type, url, data, config, socket, cache = {}, isDebounce = false) {
  ...

  return new Promise(function(resolve, reject) {
    if (cacheData) {
      resolve(cacheData);
    } else {
      const fn = () => {
        // 请求接口代码
        http
          .then(function(res) {
            ...
          })
          .catch(function(res) {
            ...
            reject(res);
          })
          .finally(() => {
            debounce().cancel()
          });
      }
      
      // 对axios请求进行防抖配置, 防抖时间为 5s
      if(isDebounce) {
        debounce(fn, 5000)()
      } else {
        fn()
      }
    }
  });
}

👉 三、实现原理

介于我们封装axios后,每次请求都会统一执行一次我们封装的函数。从而统一在函数内进行防抖判断,防止短时间发出大量误触请求!

因为小温是在项目后期进行功能优化,所以以入参的形式(默认关闭)控制是否开启防抖功能!

难点:由于防抖函数位于axios封装方法中,所以每次请求都无法获取到上次执行遗留下来的timer。相当于每次执行的防抖函数都为新的函数,导致timer变量无法被闭包存储,无法起到请求防抖的功能! 故而通过将timer暂存至本地,解决问题!

给防抖函数增加中断防抖的功能,在请求响应后通过cancel函数关闭当前防抖流程!

👉 结论

本篇文章仅是基于实际开发中,对防抖概念的实际应用。可能部分逻辑存在问题,需要各位小伙伴在使用时,根据实际场景做修改! 本文仅用于思路指导!在实际运用还是存在问题: 比如当存在两个及以上接口同时请求时,会使防抖函数失效,导致后请求的接口被强行取消。

这个问题也需要重点去解决! 但是本项目中,仅用于列表接口查询时的防抖,故暂不解决这个问题!

原因: 出现问题的原因也很简单, 由于 timer 只存一个参数,防抖函数无法准确的判断防抖对象, 就是同时请求的接口,后面的接口被当作第一个触发的请求接口的抖动请求(也就是防抖防错对象了),故被防抖阻止了。

解决思路: 将本地存储的数据,存储为object类型, 按接口地址 Url 作为 key值存储 timer,请求之前,查询当前 Url,在本地存储中查询有没有正在执行的请求!若有,则进入防抖。反之,则执行正常请求流程!

👉 补充优化: 解决多个接口请求,拦截掉了需要的请求

> 防抖函数

const debounce = (fn, delay, url = '', immediate = true) => {
  // 1.定义一个定时器, 保存上一次的定时器

  let timeout = JSON.parse(localStorage.getItem(url)) || null
  // window.console.log(url, timeout)
  // 2.真正执行的函数
  const _debounce = function() {
    let context = this;
    let args = arguments;

    if (timeout) clearTimeout(timeout); // timeout 不为null
    ... 中间内容不变
    localStorage.setItem(url, timeout)
  }

  // 封装取消功能
  _debounce.cancel = function() {
    let timeout_cancel = JSON.parse(localStorage.getItem(url)) || null
    if (timeout_cancel) clearTimeout(timeout_cancel)
    timeout = null
    localStorage.removeItem(url)
  }

  return _debounce
}

export default debounce;

> 引用位置

新增入参 Url ,请求地址,如果怕接口信息被网站获取,导致泄漏! 可以以斜杠为分割字符串,使用sqit('/')分割! 取最后一个作为本地存储的标记(key)值

image.png

最后的最后,如果觉得小温这篇文章对你有所帮助,请不要吝惜你的小手,给小温三连支持一下吧~ 😘

相关文章
|
1月前
|
资源调度 JavaScript 前端开发
vue-element-admin 综合开发四:axios安装和封装、mock安装/学习/使用
这篇文章是关于如何在Vue项目中使用axios进行网络请求、二次封装axios以及使用mockjs模拟响应数据的教程。
76 1
vue-element-admin 综合开发四:axios安装和封装、mock安装/学习/使用
|
17天前
|
JavaScript 前端开发 Java
SpringBoot项目的html页面使用axios进行get post请求
SpringBoot项目的html页面使用axios进行get post请求
40 2
|
1月前
|
Python
axios的get请求传入数组参数
【10月更文挑战第11天】 当使用 `axios` 发送包含数组参数的 GET 请求时,默认的序列化方式可能与后端(如 Django)不兼容,导致无法正确获取数组参数。解决方案是通过 `paramsSerializer` 指定自定义序列化函数,或使用 `qs` 库来格式化数组参数,确保前后端一致。示例代码展示了如何使用 `qs` 库设置 `arrayFormat` 为 `"repeat"`,以符合 Django 的解析要求。
27 2
|
1月前
vue3 + Ts 中 使用 class 封装 axios
【10月更文挑战第8天】
108 1
|
1月前
|
JSON JavaScript 前端开发
axios的post请求,数据为什么要用qs处理?什么时候不用?
axios的post请求,数据为什么要用qs处理?什么时候不用?
|
30天前
|
前端开发 JavaScript API
自己动手封装axios通用方法并上传至私有npm仓库:详细步骤与实现指南
自己动手封装axios通用方法并上传至私有npm仓库:详细步骤与实现指南
73 0
|
1月前
|
前端开发 JavaScript UED
axios取消请求CancelToken的原理解析及用法示例
axios取消请求CancelToken的原理解析及用法示例
89 0
|
1月前
|
资源调度 JavaScript
|
3月前
|
JavaScript 前端开发
【Vue面试题二十五】、你了解axios的原理吗?有看过它的源码吗?
这篇文章主要讨论了axios的使用、原理以及源码分析。 文章中首先回顾了axios的基本用法,包括发送请求、请求拦截器和响应拦截器的使用,以及如何取消请求。接着,作者实现了一个简易版的axios,包括构造函数、请求方法、拦截器的实现等。最后,文章对axios的源码进行了分析,包括目录结构、核心文件axios.js的内容,以及axios实例化过程中的配置合并、拦截器的使用等。
【Vue面试题二十五】、你了解axios的原理吗?有看过它的源码吗?
|
1月前
|
缓存 JavaScript 搜索推荐