Vue + Axios全局接口防抖、节流封装实现

Vue + Axios全局接口防抖、节流封装实现

你是否在项目中会遇到过? 

在项目中按钮点击做防连点?在请求一个接口中防止一个接口被多次请求?或者你要做一个点赞,防止那种坏坏的人,多次点击,疯狂点击........等一系列类似的问题。

如果有!!!!!!

那么你就要往下读此文章了。

什么是接口防抖和节流?

接口防抖(Debouncing)和节流(Throttling)是前端开发中常用的技术,用于限制和控制事件触发频率。

  1.  接口防抖(Debouncing):
       接口防抖是指在事件被触发后,延迟一段时间执行相应的操作,如果在延迟时间内再次触发了该事件,则重新计时。防抖的目的是减少事件触发频率,避免在短时间内多次触发事件而导致多次执行相应的操作。常见的应用场景包括搜索框输入联想、窗口大小调整等需要限制频率的场景。
  2. 接口节流(Throttling):
       接口节流是指在一定时间间隔内,只允许事件触发一次,即使在该时间间隔内多次触发该事件,也只会执行一次相应的操作。节流的目的是控制事件触发频率,避免在短时间内多次触发事件而导致过多的资源消耗。常见的应用场景包括滚动加载、按钮点击等需要限制频率的场景。

接口防抖和节流都是为了在频繁触发事件时提供优化和控制的机制。它们可以帮助提高前端应用的性能和用户体验,减少不必要的请求和操作,避免过度消耗资源。具体选择使用哪种方式,取决于具体的应用场景和需求。

Vue + Axios 封装全局接口防抖和节流配置

在 Vue 中,可以通过创建一个全局的 axios 实例来封装接口请求。下面我们将根据需求,对 axios 实例进行编写,实现防抖和节流功能。

防抖

在实现防抖之前,我们先来介绍一下什么是“防抖”。在前端开发中,“防抖”指的是在一定时间内只能触发一次事件,通常是输入框或滚动事件。假如没有防抖控制,页面会出现一些异常情况,例如:搜索框输入过快、滚动条跳动频繁等。

防抖的实现原理非常简单,就是通过对要执行的函数进行延迟处理,以此来控制函数执行的次数。具体流程如下:

  1. 定义一个变量用于保存计时器。
  2. 在函数执行前判断计时器是否存在,如果存在则清除计时器。
  3. 为函数设置时间延迟,将返回结果保存到计时器变量中。
  4. 等待时间超过设定的阈值后,执行相应的回调函数。

下面是防抖代码的示例:

// 防抖
function debounce(fn, delay = 500) {
  let timer = null;
  return function(...args) {
    if (timer !== null) {
      clearTimeout(timer);
    }
    timer = setTimeout(() => {
      fn.apply(this, args);
      timer = null;
    }, delay);
  };
}

注意事项

在使用防抖技术的时候,需要注意以下几点:

  1. 时间延迟需要根据业务需求进行调整。
  2. 在防抖过程中,要确保函数参数传递正确。

节流

 

相比于防抖技术,节流技术更加灵活。在前端开发中,“节流”通常指的是在一定时间内只能执行一次事件,例如:下拉加载更多、页面滚动等。

实现原理

节流技术的实现原理也非常简单,就是通过设置一个固定时间间隔,在这个时间间隔内只能执行一次相应的回调函数。具体流程如下:

  1. 定义一个变量用于保存上一次执行函数的时间。
  2. 在执行函数前获取当前的时间戳。
  3. 判断当前时间与上一次执行时间是否大于设定的间隔时间,如果大于,则执行相应的回调函数,并更新上一次执行时间。
  4. 如果小于设定的间隔时间,则等待下一次执行。

下面是节流代码的示例:

// 节流
function throttle(fn, delay = 500) {
  let last = 0;
  return function(...args) {
    let now = new Date().getTime();
    if (now - last > delay) {
      last = now;
      fn.apply(this, args);
    }
  };
}

一个完整示例

import axios from 'axios'

function request(config) {
  const instance = axios.create({
    baseURL: 'http://localhost:3000/api',
    timeout: 10000
  })

// 防抖
const debounceTokenCancel = new Map()
instance.interceptors.request.use(config => {
  const tokenKey = `${config.method}-${config.url}`
  const cancel = debounceTokenCancel.get(tokenKey)
  if (cancel) {
    cancel()
  }
  return new Promise(resolve => {
    const timer = setTimeout(() => {
      clearTimeout(timer)
      resolve(config)
    }, 800)
    debounceTokenCancel.set(tokenKey, () => {
      clearTimeout(timer)
      resolve(new Error('取消请求'))
    })
  })
}, error => {
  console.log(error)
  return Promise.reject(error)
})

instance.interceptors.response.use(response => {
  return response
}, error => {
  console.log(error)
  return Promise.reject(error)
})

// 节流
let lastTime = new Date().getTime()
instance.interceptors.request.use(config => {
  const nowTime = new Date().getTime()
  if (nowTime - lastTime < 1000) {
    return Promise.reject(new Error('节流处理中,稍后再试'))
  }
  lastTime = nowTime
  return config
}, error => {
  console.log(error)
  return Promise.reject(error)
})

return instance(config)
}

export default request

 以上来自于网络作者

作者:ShihHsing
链接:https://juejin.cn/post/7225133152490160187
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

下面我们来看看我们从chatGPT上的回答:

  1. 创建一个新的文件(例如api.js),用于封装Axios请求:
import axios from 'axios';

const instance = axios.create({
  baseURL: 'your_base_url_here',
  timeout: 5000, // 设置请求超时时间
});

// 全局的接口防抖
let debounceTimer = null;

function debounce(func, delay) {
  clearTimeout(debounceTimer);
  debounceTimer = setTimeout(func, delay);
}

// 全局的接口节流
let throttleTimer = null;
let lastRequestTime = 0;

function throttle(func, delay) {
  const currentTime = Date.now();
  const remainingTime = delay - (currentTime - lastRequestTime);
  clearTimeout(throttleTimer);

  if (remainingTime <= 0) {
    func();
    lastRequestTime = currentTime;
  } else {
    throttleTimer = setTimeout(func, remainingTime);
  }
}

// 封装get请求
function get(url, config) {
  return instance.get(url, config);
}

// 封装post请求
function post(url, data, config) {
  return instance.post(url, data, config);
}

export default {
  debounce,
  throttle,
  get,
  post,
};
  1. 在Vue的入口文件(例如main.js)中,全局注册api.js中封装的方法:
import Vue from 'vue';
import api from './api.js';

Vue.prototype.$api = api;

 现在,你可以在Vue组件中使用全局的接口防抖和节流方法了。下面是一个示例:

<template>
  <div>
    <button @click="debounceRequest">Debounce Request</button>
    <button @click="throttleRequest">Throttle Request</button>
  </div>
</template>

<script>
export default {
  methods: {
    debounceRequest() {
      this.$api.debounce(() => {
        // 在这里执行需要防抖的请求
      }, 500);
    },
    throttleRequest() {
      this.$api.throttle(() => {
        // 在这里执行需要节流的请求
      }, 500);
    },
  },
};
</script>

这样,当按钮被点击时,请求将会被防抖或节流,根据需要调整防抖和节流的时间间隔。请确保根据实际需求进行配置和调整。

这只是一种封装实现的方式,你可以根据具体项目的需求进行修改和扩展。希望对你的前端开发有所帮助!

当然你可能看出来他对于api.js的封装不是太完美,那么我们继续对他进行提问:

我想让headers有一个固定的内容,通过请求,如果不传就用固定的,传了采用传递的值

import axios from 'axios';

const instance = axios.create({
  baseURL: 'your_base_url_here',
  timeout: 5000, // 设置请求超时时间
});

// 全局的接口防抖
let debounceTimer = null;

function debounce(func, delay) {
  clearTimeout(debounceTimer);
  debounceTimer = setTimeout(func, delay);
}

// 全局的接口节流
let throttleTimer = null;
let lastRequestTime = 0;

function throttle(func, delay) {
  const currentTime = Date.now();
  const remainingTime = delay - (currentTime - lastRequestTime);
  clearTimeout(throttleTimer);

  if (remainingTime <= 0) {
    func();
    lastRequestTime = currentTime;
  } else {
    throttleTimer = setTimeout(func, remainingTime);
  }
}

// 封装get请求
function get(url, params, config = {}) {
  const defaultHeaders = {
    'Content-Type': 'application/json', // 设置默认的请求头
    // 添加其他默认请求头字段...
  };

  const headers = config.headers ? { ...defaultHeaders, ...config.headers } : defaultHeaders;

  return instance.get(url, {
    ...config,
    headers,
    params,
  });
}

// 封装post请求
function post(url, data, config = {}) {
  const defaultHeaders = {
    'Content-Type': 'application/json', // 设置默认的请求头
    // 添加其他默认请求头字段...
  };

  const headers = config.headers ? { ...defaultHeaders, ...config.headers } : defaultHeaders;

  return instance.post(url, data, {
    ...config,
    headers,
  });
}

// 封装put请求
function put(url, data, config = {}) {
  const defaultHeaders = {
    'Content-Type': 'application/json', // 设置默认的请求头
    // 添加其他默认请求头字段...
  };

  const headers = config.headers ? { ...defaultHeaders, ...config.headers } : defaultHeaders;

  return instance.put(url, data, {
    ...config,
    headers,
  });
}

// 封装delete请求
function del(url, config = {}) {
  const defaultHeaders = {
    'Content-Type': 'application/json', // 设置默认的请求头
    // 添加其他默认请求头字段...
  };

  const headers = config.headers ? { ...defaultHeaders, ...config.headers } : defaultHeaders;

  return instance.delete(url, {
    ...config,
    headers,
  });
}

export default {
  debounce,
  throttle,
  get,
  post,
  put,
  del,
};

 当然我还问了一些其他的问题,这里就不一一列举出来了。所以小伙伴们,我们在尽可能理想的情况下,尽量对我们的封装去进行拓宽和完善来达到它的健壮!

 

 

posted @ 2023-07-13 15:35  上官靖宇  阅读(919)  评论(0编辑  收藏  举报