由于业务中查询页面接口定时轮询,使用方法不对的话,可能导致页面很卡,或者因为接口返回时序不符合预期,导致渲染结果错误,如何避免这些坑呢?
1. 定时轮询,你的第一想法是怎么使用呢
1. 1. 想法一:无脑轮询 setInterval
如果接口返回时间 < 轮询时间,还勉强能使用。一旦接口慢,接口返回时间 > 轮询时间,就会导致浏览器请求堆积,请求都处于排队中,从而导致页面就很卡。因此就想到了第二种方法,有条件的轮询,等到上次的返回结果才发起请求。
1. 2. 想法二:有条件轮询,等上次返回后才开始下次轮询
由于业务需求,多个页面用到了定时轮询,这个时候得封装一个类了
class CustomRequest {
constructor(fn,interval=5000){
this.fn = fn();
this.interval = interval;
this._SID = null;
// 用于控制停止轮询
this.stoped = false;
this.run();
}
run(){
this.fn().then(()=>{
if(this.stoped ==false){
this._SID = setTimeout(()=>{
this.run();
}, this.interval));
}
});
}
// 停止轮询
stop(){
this.stoped = true;
clearTimeout(this._SID);
}
}
2. 当用户打开N个tab页时
有用户吐槽说,页面很卡,请求也是很慢很慢。我百思不解🤔,明明我打开页面很快,接口返回也很流畅。用户发了一张接口请求图,上面大部分请求都处于stalled时间很长,也就是说很多接口都处于等待状态。
后来才知道,用户打开了很多个页面,其中有好几个页面都在处于定时请求接口。而浏览器对目标服务器最多能建立的请求连接是6个。超过6个就会处于排队状态了
这里能做的优化则是,在系统页面跳转的时候,尽可能在当前tab页跳转,而不是新打开一个tab页
3. 请求返回结果时序不符合预期,导致渲染结果不对
背景是这样的,页面同一个接口请求,A请求先开始请求,B请求后开始请求,A请求返回结果很慢数据很多,B请求返回很快数据量很少;导致最终渲染的是A请求的结果。
于是开始新的一轮解决方案,B请求发起后,放弃A的请求结果或者取消A的请求。正好网上看到了axios的cancleToken,能够取消请求然后不返回结果。
import axios from 'axios';
const CancelToken = axios.CancelToken;
class CancelTokenAxios {
constructor() {
this.cancel = null;
}
request(config) {
const me = this;
if (this.cancel) {
this.cancel();
}
return new Promise((resolve, reject) => {
axios({
...config,
cancelToken: new CancelToken(function executor(c) {
me.cancel = c;
}),
}).then((res) => {
// 业务自定义逻辑
if (res.errno==0) {
resolve(res);
} else {
reject();
}
}, (err) => {
console.log(err);
});
});
}
}
module.exports = CancelTokenAxios;