编辑
2024-03-12
面试题
00
请注意,本文编写于 179 天前,最后修改于 75 天前,其中某些信息可能已经过时。

今日问题:防止接口重复调用的前端解决方案。

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

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

  1. 防抖: 这种方法适用于防止连续快速的点击事件导致的重复调用。通过设置一个延迟时间,在这个时间内如果再次触发事件,则重新计时。
js
// 使用lodash的debounce函数来实现防抖 import _ from 'lodash'; function fetchData() { // 触发请求的函数 } // 防抖函数,等待300ms后执行 const debouncedFetchData = _.debounce(fetchData, 300); // 在事件处理函数中使用 button.addEventListener('click', debouncedFetchData);
  1. 节流: 与防抖类似,节流是确保函数在一定时间内只执行一次。这适用于例如滚动事件,确保在滚动过程中不会发送太多的调用请求。
js
// 使用lodash的throttle函数来实现节流 import _ from 'lodash'; function fetchData() { // 触发请求的函数 } // 节流函数,每1000ms内最多执行一次 const throttledFetchData = _.throttle(fetchData, 1000); // 在事件处理函数中使用 button.addEventListener('click', throttledFetchData);
  1. 采用禁用按钮的方式:禁用按钮:在发送请求之前,禁用按钮(利用loading或者disabled属性),直到请求完成后再启用它。这可以防止用户在请求进行中多次点击按钮。
html
<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对象当中是否已经存在该请求信息的请求,如果存在取消上次请求。
js
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,则阻止新的请求。
js
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. 请求缓存: 对于相同的请求,可以缓存结果。当再次遇到相同的请求时,直接从缓存中获取结果,而不是重新调用接口。
js
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. 请求队列: 将请求放入队列中,一次只处理一个请求。完成一个请求后,再从队列中取出下一个请求进行处理。
js
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. 请求标识: 为每个请求生成一个唯一标识符,如果检测到相同的标识符,则阻止该请求。
js
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)来记录已发送的请求和它们的参数,以避免在短时间内发送相同的请求。
js
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对象来控制异步操作,确保在前一个请求未完成前,不会发起新的请求。
js
let fetchPromise = null; function fetchData() { if (fetchPromise) return fetchPromise; fetchPromise = fetch('/api/data') .then(response => response.json()) .finally(() => { fetchPromise = null; }); return fetchPromise; }

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

如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:CreatorRay

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!