几行代码,优雅的避免接口重复请求!同事都说好!

往期精彩文章:拿客户电脑,半小时完成轮播组件开发!被公司奖励500!

背景简介

我们日常开发中,经常会遇到点击一个按钮或者进行搜索时,请求接口的需求。

如果我们不做优化,连续点击按钮或者进行搜索,接口会重复请求。

首先,这会导致性能浪费!最重要的,如果接口响应比较慢,此时,我们在做其他操作会有一系列bug!

那么,我们该如何规避这种问题呢?

如何避免接口重复请求

防抖节流方式(不推荐)

使用防抖节流方式避免重复操作是前端的老传统了,不多介绍了

防抖实现

<template>
  <div>
    <button @click="debouncedFetchData">请求</button>
  </div>
</template>
<script setup>
import { ref } from 'vue';
import axios from 'axios';

const timeoutId = ref(null);

function debounce(fn, delay) {
  return function(...args) {
    if (timeoutId.value) clearTimeout(timeoutId.value);
    timeoutId.value = setTimeout(() => {
      fn(...args);
    }, delay);
  };
}

function fetchData() {
  axios.get('http://api/gcshi)  // 使用示例API
    .then(response => {
      console.log(response.data);
    })
}

const debouncedFetchData = debounce(fetchData, 300);
</script>

防抖(Debounce)

  • 在setup函数中,定义了timeoutId用于存储定时器ID。
  • debounce函数创建了一个闭包,清除之前的定时器并设置新的定时器,只有在延迟时间内没有新调用时才执行fetchData。
  • debouncedFetchData是防抖后的函数,在按钮点击时调用。

节流实现

<template>
  <div>
    <button @click="throttledFetchData">请求</button>
  </div>
</template>
<script setup>
import { ref } from 'vue';
import axios from 'axios';

const lastCall = ref(0);

function throttle(fn, delay) {
  return function(...args) {
    const now = new Date().getTime();
    if (now - lastCall.value < delay) return;
    lastCall.value = now;
    fn(...args);
  };
}

function fetchData() {
  axios.get('http://api/gcshi')  //
    .then(response => {
      console.log(response.data);
    })
}

const throttledFetchData = throttle(fetchData, 1000);
</script>

节流(Throttle)

  • 在setup函数中,定义了lastCall用于存储上次调用的时间戳。
  • throttle函数创建了一个闭包,检查当前时间与上次调用时间的差值,只有大于设定的延迟时间时才执行fetchData。
  • throttledFetchData是节流后的函数,在按钮点击时调用。

节流防抖这种方式感觉用在这里不是很丝滑,代码成本也比较高,因此,很不推荐!

请求锁定(加laoding状态)

请求锁定非常好理解,设置一个laoding状态,如果第一个接口处于laoding中,那么,我们不执行任何逻辑!

<template>
  <div>
    <button @click="fetchData">请求</button>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import axios from 'axios';

const laoding = ref(false);

function fetchData() {
  // 接口请求中,直接返回,避免重复请求
  if(laoding.value) return
  laoding.value = true
  axios.get('http://api/gcshi')  //
    .then(response => {
      laoding.value = fasle
    })
}

const throttledFetchData = throttle(fetchData, 1000);
</script>

这种方式简单粗暴,十分好用!

但是也有弊端,比如我搜索A后,接口请求中;但我此时突然想搜B,就不会生效了,因为请求A还没响应

因此,请求锁定这种方式无法取消原先的请求,只能等待一个请求执行完才能继续请求。

axios.CancelToken取消重复请求

基本用法

axios其实内置了一个取消重复请求的方法:axios.CancelToken,我们可以利用axios.CancelToken来取消重复的请求,爆好用!

首先,我们要知道,aixos有一个config的配置项,取消请求就是在这里面配置的。

<template>
  <div>
    <button @click="fetchData">请求</button>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import axios from 'axios';

let cancelTokenSource = null;


function fetchData() {
  if (cancelTokenSource) {
    cancelTokenSource.cancel('取消上次请求');
    cancelTokenSource = null;
  }
  cancelTokenSource = axios.CancelToken.source();
  
  axios.get('http://api/gcshi',{cancelToken: cancelTokenSource.token})  //
    .then(response => {
      laoding.value = fasle
    })
}

</script>

我们测试下,如下图:可以看到,重复的请求会直接被终止掉!

CancelToken官网示例

官网使用方法传送门:https://www.axios-http.cn/docs/cancellation

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.');

也可以通过传递一个 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();

注意: 可以使用同一个 cancel token 或 signal 取消多个请求。

在过渡期间,您可以使用这两种取消 API,即使是针对同一个请求:

const controller = new AbortController();

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

axios.get('/user/12345', {
  cancelToken: source.token,
  signal: controller.signal
}).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.');
// 或
controller.abort(); // 不支持 message 参数

往期精彩文章:拿客户电脑,半小时完成轮播组件开发!被公司奖励500!

相关推荐

  1. 用过API接口汇总,含免费次数

    2024-07-10 10:48:05       65 阅读
  2. react native hooks 如何避免重复请求

    2024-07-10 10:48:05       35 阅读
  3. 大批量接口请求前端优化

    2024-07-10 10:48:05       37 阅读
  4. 功能问题:如何防止接口重复请求

    2024-07-10 10:48:05       32 阅读
  5. 可以写后端接口

    2024-07-10 10:48:05       18 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-10 10:48:05       99 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-10 10:48:05       107 阅读
  3. 在Django里面运行非项目文件

    2024-07-10 10:48:05       90 阅读
  4. Python语言-面向对象

    2024-07-10 10:48:05       98 阅读

热门阅读

  1. 深入解析CSS中的!important规则:优先级与最佳实践

    2024-07-10 10:48:05       33 阅读
  2. Django中模型的基于类的混入

    2024-07-10 10:48:05       25 阅读
  3. Impala写Parquet文件

    2024-07-10 10:48:05       26 阅读
  4. C# 反射

    2024-07-10 10:48:05       27 阅读
  5. 在程序中引用cuda.memory函数监控GPU内存

    2024-07-10 10:48:05       31 阅读
  6. LlamaInde相关学习

    2024-07-10 10:48:05       35 阅读
  7. LeetCode每日一题 分发糖果

    2024-07-10 10:48:05       33 阅读
  8. 刷算法Leetcode---9(二叉树篇Ⅲ)

    2024-07-10 10:48:05       31 阅读
  9. 【GC 死亡对象判断】

    2024-07-10 10:48:05       25 阅读
  10. [ABC275A] Find Takahashi 题解

    2024-07-10 10:48:05       24 阅读
  11. 洛谷 P2141 [NOIP2014 普及组] 珠心算测验

    2024-07-10 10:48:05       27 阅读