取消重复请求
使用唯一标识和Map存储
通过为每个请求生成一个唯一标识,并将它们存储在Map中,可以检测并取消重复的请求
js
const pendingRequests=new Map();
function generateKey(config) {
// 根据请求方法和 URL 生成唯一的键
return `${config.method}:${config.url}`;
}
function addRequest(config) {
const key = generateKey(config);
if (pendingRequests.has(key)) {
// 如果请求已存在则取消
const cancelToken = pendingRequests.get(key);
cancelToken.cancel('Request canceled due to duplicate.');
}
const cancelToken = axios.CancelToken.source();
config.cancelToken = cancelToken.token;
pendingRequests.set(key, cancelToken);
}
function removeRequest(config) {
const key = generateKey(config);
pendingRequests.delete(key);
}
js
// 使用示例
axios.interceptors.request.use((config) => {
addRequest(config);
return config;
});
axios.interceptors.response.use(
(response) => {
removeRequest(response.config);
return response;
},
(error) => {
removeRequest(error.config || {});
return Promise.reject(error);
}
);
通过axios的请求和响应拦截器,管理每个请求的取消标识,如果请求重复,之前的请求会被取消
使用AbortController
AbortController 是现代浏览器支持的一种用于取消 fetch 请求的方法。可以将 AbortController 与 fetch 请求结合使用,在发起新的请求时取消未完成的相同请求。
js
const controllers = new Map();
function fetchWithCancel(url, options = {}) {
// 如果请求已经存在则取消
if (controllers.has(url)) {
controllers.get(url).abort();
}
const controller = new AbortController();
const signal = controller.signal;
controllers.set(url, controller);
return fetch(url, { ...options, signal })
.then((response) => {
controllers.delete(url);
return response;
})
.catch((error) => {
controllers.delete(url);
if (error.name === 'AbortError') {
console.log('Request was canceled');
} else {
throw error;
}
});
}
// 使用示例
fetchWithCancel('/api/data');
fetchWithCancel('/api/data'); // 第二个请求会取消第一个
防抖debounce 和节流throttle
防抖——一段时间内只执行最后一次操作,适合用户停止输入后再发送请求
js
function debounce(fn, delay) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
// 使用示例
const search = debounce((query) => {
fetchWithCancel(`/api/search?query=${query}`);
}, 300);
节流——在规定事件内只执行一次,适合滚动或点击等频繁触发的请求
js
function throttle(fn, interval) {
let lastTime = 0;
return function (...args) {
const now = Date.now();
if (now - lastTime >= interval) {
lastTime = now;
fn.apply(this, args);
}
};
}
// 使用示例
const fetchData = throttle(() => {
fetchWithCancel('/api/data');
}, 1000);
标记唯一请求ID
对于某些 API 请求,可以为每次请求添加唯一 ID,通过在后端检查该 ID 来过滤重复请求。这种方法通常需要后端配合。
示例:
在每次请求中生成唯一 ID 并传给后端,后端检查是否已有相同的请求正在处理中,如果有则忽略新请求。
可以用 UUID 或其他方法生成唯一请求标识符,并通过请求头或请求体传递。
设置请求队列(请求去重)
对于短时间内发起的相同请求,可以使用请求队列实现请求去重
js
const requestQueue = {};
function uniqueRequest(url) {
if (requestQueue[url]) {
return requestQueue[url]; // 返回已存在的请求
}
requestQueue[url] = fetch(url)
.then((response) => response.json())
.finally(() => {
delete requestQueue[url]; // 请求完成后移出队列
});
return requestQueue[url];
}
// 使用示例
uniqueRequest('/api/data');
uniqueRequest('/api/data'); // 第二次请求会复用第一次请求