- 作者:老汪软件技巧
- 发表时间:2024-08-27 15:02
- 浏览量:
var xhr = new XMLHttpRequest(),
method = "GET",
url = "https://developer.mozilla.org/";
xhr.open(method, url, true);
xhr.send();
if (OH_NOES_WE_NEED_TO_CANCEL_RIGHT_NOW_OR_ELSE) {
xhr.abort();
}
如果用fetch,也有AbortController可以取消
const controller = new AbortController();
const signal = controller.signal;
const url = "video.mp4";
const downloadBtn = document.querySelector(".download");
const abortBtn = document.querySelector(".abort");
downloadBtn.addEventListener("click", fetchVideo);
abortBtn.addEventListener("click", () => {
controller.abort();
console.log("Download aborted");
});
function fetchVideo() {
fetch(url, { signal })
.then((response) => {
console.log("Download complete", response);
})
.catch((err) => {
console.error(`Download error: ${err.message}`);
});
}
对于常用的Axios,支持以 fetch API 方式——AbortController取消请求
const controller = new AbortController();
async function getOpinionList (time) {
const res = await axios.post('https://xxx', {
signal: controller.signal
})
await new Promise((resolve) => {
setTimeout(() => {
resolve();
}, time)
})
return Promise.resolve(res);
}
let res;
function fetchData (name, time) {
controller.abort();// 取消请求
getOpinionList(name, time).then(function(response) {
res = { name };
});
}
fetchData('A请求', 3000);
fetchData('B请求', 2000);
fetchData('C请求', 1000);
setTimeout(() => {
console.log(res);
}, 4000)
请求结果保存的是最后触发的C请求
3.requestId
用特殊字符当成requestId,利用axios的请求拦截器,在请求头上加上唯一标识,本地存储最后请求的唯一标识符。
const axiosInstance = axios.create();
const localStorage = {
lastRequestId: 0,
lastRequestName: undefined
}
let list = [];
// 添加请求拦截器
axiosInstance.interceptors.request.use(config => {
// 生成一个唯一的请求ID,这里使用时间戳作为示例
const requestId = `${Date.now()}`;
// 将requestId添加到请求的headers中
config.headers['X-Request-Id'] = requestId;
config.headers['X-Request-name'] = encodeURIComponent(config.data.name);
// 收集到的三次请求的时间戳是一样的,requestId不能用Date.now(),应该用UUID
list.push(requestId);
// 可以将requestId存储起来,例如在localStorage或全局状态管理中
localStorage['lastRequestId'] = requestId;
localStorage['lastRequestName'] = config.data.name;
// 返回修改后的配置
return config;
}, error => {
// 请求错误处理
return Promise.reject(error);
});
async function getOpinionList (name,time) {
const res = await axiosInstance.post('https://xxx',{name});
await new Promise((resolve) => {
setTimeout(() => {
resolve();
}, time)
})
return Promise.resolve(res);
}
let res;
function fetchData (name, time) {
getOpinionList(name, time).then(function(response) {
const rName = decodeURIComponent(response.config.headers['X-Request-name']);
console.log('响应的请求', rName);
if (rName === localStorage['lastRequestName']) {
res = { name };
}
});
}
fetchData('A请求', 3000);
fetchData('B请求', 2000);
fetchData('C请求', 1000);
setTimeout(() => {
console.log(localStorage)
console.log(list)
console.log('存储的结果',res);
}, 4000)
在测试过程中发现,如果单纯用Date.now()当成requestId,则三次请求的时间戳都是一样的,就会导致不准确,所以requestId不能单纯使用时间戳,而是用UUID的形式,测试demo是用了lastRequestName存储唯一标识。请求结果如
4.时间戳
让后端返回一个时间戳,每次都判断,保证永远只保存最后一次发起的请求的时间戳的数据即可。
function getOpinionList (time) {
return axios.post('https://xxx')
}
let res;
let maxTimestamp = 0;// 记录最后一次请求的时间戳,依旧大小更新
const list = [];
function fetchData (name) {
getOpinionList(name).then(function(response) {
const timestamp = response.data.timestamp;
list.push({ name, timestamp});
if (timestamp > maxTimestamp) {
res = { name ,timestamp};
}
});
}
fetchData('A请求', 5000);
fetchData('B请求', 3000);
fetchData('C请求', 1000);
setTimeout(() => {
console.log('各请求时间戳',list)
console.log('存储结果',res);
}, 6000)
结果如
总结
本文介绍了4种解决竞态条件的处理方案,其中方案一是在Vue3的watch设计中学来的,不失为一种虽然有点绕,但是极为优雅的处理方式,不依赖于第三方插件功能或者是其他的附加内容信息,单单依靠JS的闭包就能实现,相当优雅了。