充分利用ChatGPT的优势,帮助我们快速准备前端面试。今日问题:防止接口重复调用的前端解决方案。
Q:在前端面试中,如果被问到,接口防止重复调用的前端解决方案都有哪些,什么回答比较好,全面、具体一些,尽量描述出所有细节和实现方案,给出必要的代码示例。
A:在前端面试中,谈论接口防止重复调用的解决方案时,可以从以下几个方面进行全面而具体的讨论:
公众号:Code程序人生,个人网站:https://creatorblog.cn
- 防抖: 这种方法适用于防止连续快速的点击事件导致的重复调用。通过设置一个延迟时间,在这个时间内如果再次触发事件,则重新计时。
// 使用lodash的debounce函数来实现防抖
import _ from 'lodash';
function fetchData() {
// 触发请求的函数
}
// 防抖函数,等待300ms后执行
const debouncedFetchData = _.debounce(fetchData, 300);
// 在事件处理函数中使用
button.addEventListener('click', debouncedFetchData);
- 节流: 与防抖类似,节流是确保函数在一定时间内只执行一次。这适用于例如滚动事件,确保在滚动过程中不会发送太多的调用请求。
// 使用lodash的throttle函数来实现节流
import _ from 'lodash';
function fetchData() {
// 触发请求的函数
}
// 节流函数,每1000ms内最多执行一次
const throttledFetchData = _.throttle(fetchData, 1000);
// 在事件处理函数中使用
button.addEventListener('click', throttledFetchData);
- 采用禁用按钮的方式:禁用按钮:在发送请求之前,禁用按钮(利用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; // 请求完成后,启用按钮
}
},
}
- 利用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);
}
);
- 状态标志: 使用变量记录请求的状态。在请求开始时设置为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);
- 请求缓存: 对于相同的请求,可以缓存结果。当再次遇到相同的请求时,直接从缓存中获取结果,而不是重新调用接口。
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;
});
}
- 请求队列: 将请求放入队列中,一次只处理一个请求。完成一个请求后,再从队列中取出下一个请求进行处理。
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();
});
}
- 请求标识: 为每个请求生成一个唯一标识符,如果检测到相同的标识符,则阻止该请求。
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;
});
}
- 客户端存储: 利用本地存储(如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;
});
}
- Promise对象: 利用Promise对象来控制异步操作,确保在前一个请求未完成前,不会发起新的请求。
let fetchPromise = null;
function fetchData() {
if (fetchPromise) return fetchPromise;
fetchPromise = fetch('/api/data')
.then(response => response.json())
.finally(() => {
fetchPromise = null;
});
return fetchPromise;
}
这些示例提供了不同策略的实现方式,可以根据具体需求进行选择和调整。