GPT每日面试题—防止接口重复调用的前端解决方案

41 篇文章 2 订阅
26 篇文章 0 订阅

充分利用ChatGPT的优势,帮助我们快速准备前端面试。今日问题:防止接口重复调用的前端解决方案。

Q:在前端面试中,如果被问到,接口防止重复调用的前端解决方案都有哪些,什么回答比较好,全面、具体一些,尽量描述出所有细节和实现方案,给出必要的代码示例。

A:在前端面试中,谈论接口防止重复调用的解决方案时,可以从以下几个方面进行全面而具体的讨论:

公众号:Code程序人生,个人网站:https://creatorblog.cn

  1. 防抖: 这种方法适用于防止连续快速的点击事件导致的重复调用。通过设置一个延迟时间,在这个时间内如果再次触发事件,则重新计时。
// 使用lodash的debounce函数来实现防抖
import _ from 'lodash';

function fetchData() {
  // 触发请求的函数
}

// 防抖函数,等待300ms后执行
const debouncedFetchData = _.debounce(fetchData, 300);

// 在事件处理函数中使用
button.addEventListener('click', debouncedFetchData);
  1. 节流: 与防抖类似,节流是确保函数在一定时间内只执行一次。这适用于例如滚动事件,确保在滚动过程中不会发送太多的调用请求。
// 使用lodash的throttle函数来实现节流
import _ from 'lodash';

function fetchData() {
  // 触发请求的函数
}

// 节流函数,每1000ms内最多执行一次
const throttledFetchData = _.throttle(fetchData, 1000);

// 在事件处理函数中使用
button.addEventListener('click', throttledFetchData);
  1. 采用禁用按钮的方式:禁用按钮:在发送请求之前,禁用按钮(利用loading或者disabled属性),直到请求完成后再启用它。这可以防止用户在请求进行中多次点击按钮。
<div id="app">    
    <button @click="sendRequest" :loading="loading">请求</button>
 </div>
 
 methods: {    
     async sendRequest() {      
         this.loading = true; // 禁用按钮      
         try {        // 发送请求        
             await yourApiRequestFunction();        // 请求成功后,启用按钮      
         } catch (error) {        // 处理错误情况      } 
         finally {        
             this.loading = false; // 请求完成后,启用按钮      
         }    
     },  
 }
  1. 利用axios取消接口的api: axios 内部提供的 CancelToken 来取消请求,通过axios请求拦截器,在每次请求前把请求信息和请求的取消方法放到一个map对象当中,并且判断map对象当中是否已经存在该请求信息的请求,如果存在取消上次请求。
const pendingRequest = new Map();

function generateReqKey(config) {
    const { method, url, params, data } = config;
    return [method, url, Qs.stringify(params), Qs.stringify(data)].join("&");
}

function addPendingRequest(config) {
    const requestKey = generateReqKey(config);
    config.cancelToken = config.cancelToken || new axios.CancelToken((cancel) => {
        if (!pendingRequest.has(requestKey)) {
            pendingRequest.set(requestKey, cancel);
        }
    });
}

function removePendingRequest(config) {
    const requestKey = generateReqKey(config);
    if (pendingRequest.has(requestKey)) {
        const cancelToken = pendingRequest.get(requestKey);
        cancelToken(requestKey);
        pendingRequest.delete(requestKey);
    }
}

// axios拦截器代码
axios.interceptors.request.use(
    function (config) {
        removePendingRequest(config); // 检查是否存在重复请求,若存在则取消已发的请求
        addPendingRequest(config); // 把当前请求信息添加到pendingRequest对象中
        return config;
    },
    (error) => {
        return Promise.reject(error);`
    }
);
axios.interceptors.response.use(
    (response) => {
        removePendingRequest(response.config); // 从pendingRequest对象中移除请求
        return response;
    },
    (error) => {
        removePendingRequest(error.config || {}); // 从pendingRequest对象中移除请求
        if (axios.isCancel(error)) {
            console.log("已取消的重复请求:" + error.message);
        } else {
            // 添加异常处理
        }
        return Promise.reject(error);
    }
);

  1. 状态标志: 使用变量记录请求的状态。在请求开始时设置为true,请求结束后设置为false。在此期间,如果状态为true,则阻止新的请求。
let isFetching = false;

function fetchData() {
  if (isFetching) return;
  isFetching = true;
  
  // 发起请求
  fetch('/api/data')
    .then(response => response.json())
    .then(data => {
      console.log(data);
      isFetching = false;
    })
    .catch(() => {
      isFetching = false;
    });
}

button.addEventListener('click', fetchData);
  1. 请求缓存: 对于相同的请求,可以缓存结果。当再次遇到相同的请求时,直接从缓存中获取结果,而不是重新调用接口。
const cache = {};

function fetchData(params) {
  const key = JSON.stringify(params);
  if (cache[key]) {
    return Promise.resolve(cache[key]);
  }
  
  return fetch('/api/data', { params })
    .then(response => response.json())
    .then(data => {
      cache[key] = data;
      return data;
    });
}
  1. 请求队列: 将请求放入队列中,一次只处理一个请求。完成一个请求后,再从队列中取出下一个请求进行处理。
const requestQueue = [];
let isProcessing = false;

function processQueue() {
  if (isProcessing || !requestQueue.length) return;
  isProcessing = true;
  
  const { url, params, resolve, reject } = requestQueue.shift();
  
  fetch(url, { params })
    .then(response => response.json())
    .then(data => {
      resolve(data);
      isProcessing = false;
      processQueue();
    })
    .catch(error => {
      reject(error);
      isProcessing = false;
      processQueue();
    });
}

function fetchData(url, params) {
  return new Promise((resolve, reject) => {
    requestQueue.push({ url, params, resolve, reject });
    processQueue();
  });
}
  1. 请求标识: 为每个请求生成一个唯一标识符,如果检测到相同的标识符,则阻止该请求。
const pendingRequests = new Set();

function fetchData(url, params) {
  const key = `${url}_${JSON.stringify(params)}`;
  if (pendingRequests.has(key)) {
    return Promise.reject(new Error('Duplicate request'));
  }
  
  pendingRequests.add(key);
  
  return fetch(url, { params })
    .then(response => response.json())
    .then(data => {
      pendingRequests.delete(key);
      return data;
    })
    .catch(error => {
      pendingRequests.delete(key);
      throw error;
    });
}
  1. 客户端存储: 利用本地存储(如localStorage)来记录已发送的请求和它们的参数,以避免在短时间内发送相同的请求。
function fetchData(url, params) {
  const key = `fetch_${url}_${JSON.stringify(params)}`;
  const cachedData = localStorage.getItem(key);
  
  if (cachedData) {
    return Promise.resolve(JSON.parse(cachedData));
  }
  
  return fetch(url, { params })
    .then(response => response.json())
    .then(data => {
      localStorage.setItem(key, JSON.stringify(data));
      return data;
    });
}
  1. Promise对象: 利用Promise对象来控制异步操作,确保在前一个请求未完成前,不会发起新的请求。
let fetchPromise = null;

function fetchData() {
  if (fetchPromise) return fetchPromise;
  
  fetchPromise = fetch('/api/data')
    .then(response => response.json())
    .finally(() => {
      fetchPromise = null;
    });
  
  return fetchPromise;
}

这些示例提供了不同策略的实现方式,可以根据具体需求进行选择和调整。

  • 11
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CreatorRay

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值