背景:请求的响应时间存在不确定性,请求次数过多时,有可能较早发起的请求会较晚响应。那么我们需要设计一套机制,确保较晚发起的请求可以在客户端就取消掉较早发起的请求。比如重复的 post
请求可能会导致服务端产生多个日志记录,而且会影响加载速度,进一步影响用户体验。例如:
对于Axios来说,可以使用内部提供的CancelToken
来取消请求
// 官网示例
const CancelToken = axios.CancelToken;
const source = CancelToken.source();('/user/12345', {cancelToken: ken
}).catch(function (thrown) {if (axios.isCancel(thrown)) {console.log('Request canceled', ssage);} else {// handle error}
});axios.post('/user/12345', {name: 'new name'
}, {cancelToken: ken
})// cancel the request (the message parameter is optional)
source.cancel('Operation canceled by the user.');
也可以使用构造函数来创建CancelToken
const CancelToken = axios.CancelToken;
let cancel;
('/user/111', {CancelToken: new CancelToken(function executor(c) {cancel = c;})
})
注意:get请求,cancelToken
放第二个参数;post请求,cancelToken
放第三个参数
可以用”请求方式+请求URL+请求参数“来作为是否重复请求的判断依据。根据这三样可以生成一个唯一的key,为每个请求创建一个专属的CancelToken,然后把key和cancel函数以键值对的形式保存到Map对象中,使用 Map 的好处是可以快速的判断是否有重复的请求
import qs from 'qs'const pendingRequest = new Map();
// GET -> params;POST -> data
const requestKey = [method, url, qs.stringify(params), qs.stringify(data)].join('&');
const cancelToken = new CancelToken(function executor(cancel) {if(!pendingRequest.has(requestKey)){pendingRequest.set(requestKey, cancel);}
})
当出现重复请求的时候,我们就可以使用 cancel 函数来取消前面已经发出的请求,在取消请求之后,我们还需要把取消的请求从 pendingRequest
中移除。
因为我们需要对所有的请求都进行处理,所以我们可以考虑使用 Axios 的拦截器机制来实现取消重复请求的功能
generateReqKey
:根据当前请求信息生成Key;function generateReqKey(config) {const { method, url, params, data } = config;return [method, url, Qs.stringify(params), Qs.stringify(data)].join("&");
}
addPendingRequest
:把当前请求信息添加到pendingRequest对象中;const pendingRequest = new Map();
function addPendingRequest(config) {const requestKey = generateReqKey(config);config.cancelToken = config.cancelToken || new axios.CancelToken((cancel) => {if (!pendingRequest.has(requestKey)) {pendingRequest.set(requestKey, cancel);}});
}
removePendingReques
:检查是否存在重复请求,若存在则取消已发的请求;function removePendingRequest(config) {const requestKey = generateReqKey(config);if (pendingRequest.has(requestKey)) {const cancelToken = (requestKey);cancelToken(requestKey);pendingRequest.delete(requestKey);}
}
quest.use(function (config) {removePendingRequest(config); // 检查是否存在重复请求,若存在则取消已发的请求addPendingRequest(config); // 把当前请求信息添加到pendingRequest对象中return config;},(error) => {ject(error);}
);
sponse.use((response) => {fig); // 从pendingRequest对象中移除请求return response;},(error) => {fig || {}); // 从pendingRequest对象中移除请求if (axios.isCancel(error)) {console.log("已取消的重复请求:" + ssage);} else {// 添加异常处理}ject(error);}
);
最终呈现的效果就是
在node_modules/axios/lib/cancel/CancelToken.js文件中:
function CancelToken(executor) { // 参数executor执行器 // 参数类型判断为函数 if (typeof executor !== 'function') {throw new TypeError('executor must be a function.');}var resolvePromise;// 实例挂载一个promise,这个promise会在变量resolvePromise执行后resolvedthis.promise = new Promise(function promiseExecutor(resolve) {resolvePromise = resolve;});var token = this; // 执行器执行,将函数cancel传递到外界executor(function cancel(message) { // 设置cancel对象if (ason) {// Cancellation has already been requestedreturn;}ason = new Cancel(message); // 外界可以通过执行resolvePromise来将该token的promise置为ason);});
}
CancelToken.source = function source() {var cancel;var token = new CancelToken(function executor(c) {cancel = c;});return {token: token,cancel: cancel}
}
由以上代码可知,cancel
对象是一个函数,当我们调用该函数后,会创建 Cancel
对象并调用 resolvePromise
方法。该方法执行后,CancelToken
对象上 promise
属性所指向的 promise
对象的状态将变为 resolved
,进而执行下方代码
// lib/adapters/xhr.js
if (config.cancelToken) { config.cancelToken.promise.then(function onCanceled(cancel) { if (!request) { return; } request.abort(); // 取消请求 reject(cancel); request = null; });
}
使用此方法后,当出现重复请求时,之前已发送且未完成的请求会被取消掉。
本文发布于:2024-02-03 04:35:27,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170690612648684.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |