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

在这里插入图片描述


👉 前言

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

今天这篇文章,主要是讲述对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)值

效果图

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

往期内容 💨

🔥 < 每日算法 - JavaScript解析:跳跃游戏 Ⅰ/ Ⅱ - 贪心 >

🔥 < 每日算法 - JavaScript解析:一文解决 “ 买卖股票 ” 系列算法题 >

🔥 < vue + ElementUi 组件封装:实现弹窗展示富文本数据,允许全文搜索高亮显示搜索内容 >

🔥 < 每日算法:一文带你认识 “ 双指针算法 ” >