JS实现请求防抖
实现一个函数:
- 对于同一个请求,如果上一次接口还没有返回,不进行下一次调用
- 接口返回后,调用该请求的所有回调函数
代码实现
- /**
- * 请求控制,对于url请求未完成之前,不发起重复的请求
- * @param {(options)=>Promise} asyncRequest fetch、axios等
- * @param {number} maxRetryCount 最大重试次数
- * @returns
- */
- function reqDebounce(asyncRequest, maxRetryCount) {
- // 收集每个请求的回调函数
- const map = new Map();
- // 记录每个请求重试的次数
- const retryReqMap = new Map();
- // 定义一个私有属性,用来判断是否是重试
- const privateRetry = Symbol('retry');
- // 返回一个Promise对象
- return function request(options, retry) {
- const { url, method, data } = options;
- // 这里生成唯一key的规则可以自己改写
- const onlyKey = `${method}_${url}_${data}`;
- return new Promise((resolve, reject) => {
- if (retry !== privateRetry) {
- if (map.has(onlyKey)) {
- map.get(onlyKey).push([resolve, reject]);
- return;
- } else {
- map.set(onlyKey, [[resolve, reject]]);
- }
- }
- asyncRequest(options)
- .then(res => {
- // 如果请求成功了,将重试次数清空
- retryReqMap.set(onlyKey, 0);
- // 调用url收集的所有回调函数
- map.get(onlyKey).forEach(([resolveFunc]) => resolveFunc(res));
- // 清空url收集的回调函数
- map.set(onlyKey, []);
- })
- .catch(ex => {
- // 已经重试的次数
- let count = retryReqMap.get(onlyKey) || 0;
- if (count < maxRetryCount) {
- // 重试次数+1
- retryReqMap.set(onlyKey, ++count);
- console.log(`第${count}次尝试重新请求${url}`);
- // 尝试重试
- request(options, privateRetry);
- } else {
- // 达到了最大重试次数,执行reject回调函数
- map.get(onlyKey).forEach(([_, rejectFunc]) => rejectFunc(ex));
- retryReqMap.set(onlyKey, 0);
- }
- });
- });
- };
- }
JavaScript
测试
- // 模拟一个异步请求
- function AsyncRequest(options) {
- const { url } = options;
- console.log(`${url} is called.`);
- // 实际开发的时候直接返回一个axios、fetch等
- // return axios(url, options);
- // 模拟axios、fetch等返回一个Promise对象
- return new Promise((resolve, reject) => {
- // 随机延迟2-5s
- const timeout = Math.floor(Math.random() * 1) + 1;
- // 模拟接口情况
- setTimeout(() => {
- Math.random() > 0.5 ? resolve(`${url} success`) : reject(`${url} error`);
- }, timeout * 1e3);
- });
- }
- // const request = reqDebounce(fetch, 3);
- const request = reqDebounce(AsyncRequest, 3);
- const opts = { method: 'get', data: 'testData' };
- const opts1 = { ...opts, url: 'url1' };
- const opts2 = { ...opts, url: 'url2' };
- request(opts1).then(console.log).catch(console.log);
- request(opts1).then(console.log).catch(console.log);
- request(opts2).then(console.log).catch(console.log);
- request(opts2).then(console.log).catch(console.log);
- // url1 is called.
- // url2 is called.
- // url1 success
- // url1 success
- // 第1次尝试重新请求url2
- // url2 is called.
- // 第2次尝试重新请求url2
- // url2 is called.
- // url2 success
- // url2 success
JavaScript
控制台打印结果不唯一,因为函数的成功与否是随机的