怎样为企业设计网站,用备案的网站做违法网站,域名和网站的建设实训报告,做拍卖网站需要多少钱在平常的开发过程中#xff0c;你可能会遇到这样一个bug。
测试#xff1a;我在测一个输入框搜索的功能时#xff0c;告诉你通过输入框输入的内容#xff0c;和最终通过输入内容搜索出来的结果对不上。
前端#xff1a;我是通过调用后端接口拿到的数据#xff0c;这明显…在平常的开发过程中你可能会遇到这样一个bug。
测试我在测一个输入框搜索的功能时告诉你通过输入框输入的内容和最终通过输入内容搜索出来的结果对不上。
前端我是通过调用后端接口拿到的数据这明显是后端返回的结果有问题啊找后端去
后端通过Postman一通自测后说道结果没问题啊找前端去
前端我来试试看一顿输入后发现没问题啊这bug我复现不出来啊
测试这个bug是偶现的
前端一通排查后发现bug的直接原因是网络问题根本原因是竞态问题导致的数据不一致喜提一个有意思的bug。
一、bug原因
举个例子
你先输入1发起请求A此时请求参数为{ searchKey: 1 };你再输入2发起请求B此时请求参数为{ searchKey: 12 }; 此时由于网络原因导致先发起的请求A的响应结果比请求B的慢 拿到响应B的结果此时页面先渲染B的响应结果;拿到响应A的结果此时页面再渲染A的响应结果。
所以最后就会发现你输入的结果跟搜索出来的结果对不上。
二、解决方案
要解决它就需要了解一个知识点那就是如何取消请求。我在发起请求B的时候把请求B取消不就搞定了么
三、如何取消请求
1. 原生XMLHttpRequest
如果用的JavaScript原生的XMLHttpRequest发起的请求可以通过调用abort方法来取消请求。
var xhr new XMLHttpRequest();
var url http://localhost:3000/data;
var timer;xhr.open(GET, url, true);xhr.onreadystatechange function() {if (xhr.readyState 4 xhr.status 200) {clearTimeout(timer); // 如果在300ms内收到响应则清除定时器var response JSON.parse(xhr.responseText);console.log(response);} else {console.log(Error: xhr.status);}
};// 设置定时器在300ms后取消请求
timer setTimeout(function() {xhr.abort();console.log(Request aborted due to timeout);
}, 300);// 发起请求
xhr.send();我这里利用XMLHttpRequest发起了一个请求如果300ms后未拿到响应我便会调用abort方法取消请求。
2. fetch
通过fetch发起的请求需要通过AbortController来实现请求的取消具体步骤如下
先通过new AbortController创建一个实例比如叫controller通过controller.signal拿到一个信号然后再发起fetch请求的时候带上这个信号然后这个请求就与这个信号关联在一起了。通过第2步的关联之后可以随时通过调用controller.abort()取消请求。
具体代码如下通过fetch发起请求还是在300ms后未拿到响应便取消请求
// 创建一个 AbortController 实例
const controller new AbortController();
const signal controller.signal;// 设置取消请求的定时器
const timeout setTimeout(() {controller.abort();console.log(Request aborted due to timeout);
}, 300); // 300ms// 发起 Fetch 请求
fetch(http://localhost:3000/data, { signal }).then(response {clearTimeout(timeout); // 清除定时器return response.json();}).then(data {console.log(data);}).catch(error {if (error.name AbortError) {console.log(Fetch aborted);} else {console.error(Error:, error);}});3、axios
其实平常开发中发请求最常用的方式还是axios它是对原生XMLHttpRequest的一个封装让我们用起来更爽。
它是通过CancelToken来取消请求的其步骤如下
通过axios上的静态属性CancelToken直接先拿到CancelToken,调用CancelToken.source()方法拿到source,发请求时通过带上source.token将请求和source相关联通过第2步的关联之后可以随时通过调用source.cancel取消请求。
完整代码如下
// 创建一个 CancelToken.source
const CancelToken axios.CancelToken;
const source CancelToken.source();// 发起 Axios 请求并传入 cancel token
axios.get(http://localhost:3000/data, {cancelToken: source.token
})
.then(response {console.log(response.data);
})
.catch(function (thrown) {if (axios.isCancel(thrown)) {console.log(Request canceled, thrown.message);} else {console.error(Error:, thrown);}
});// 在需要的时候取消请求
setTimeout(() {source.cancel(Request canceled due to timeout);
}, 300); // 300msaxios底层也是通过abort方法来实现的。 四、应用场景
那么取消请求有哪些应用场景呢
连续搜索那就是上面提到的bug在连续发起多个请求后就可能会出现竞态问题引发bug大文件上传比如在做一个大文件上传功能时用户上传文件后页面显示了实时进度条以及取消上传按钮假如用户此时点击了取消按钮就应该把已经发送但未拿到响应的请求取消掉。
五、小结
上面主要介绍了通过xhr、fetch以及axios发起的请求如何取消xhr是通过abort方法来取消请求fetch则是借助了AbortController类来实现而axios虽然表面是借助了CancelToken来实现实际底层还是调用xhr.abort()方法来实现的。