一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第11天,点击查看活动详情。
前言
最近由于我们的后台同学优化了分组算法,导致接口会延迟几秒返回数据。我们的产品mm呢,就要求前端添加loading效果,等待算法的完成并展示数据。刚开始我接到需求,这简单啊,加个loading就能解决,原有逻辑全部不变。嗨嘿嘿,没有这么简单。首先,页面展示的数据有了展示优先级,在压测时间内我们需要轮询请求接口来拿到正确的结果并展示。OK,确定这一点我立马开始了。
第一版
handlePolling(fn,delay) {
if (this.trainTimer) {
clearInterval(this.trainTimer)
this.trainTimer = null
this.trainLoading = false
this.trainCount = 0
}
this.trainLoading = true
fn()
this.trainTimer = setInterval(() => {
fn()
}, delay)
}
demo(){
//记录发送次数。大于压测时间直接结束轮询
this.trainCount++
if(this.trainCount >= 5){
clearInterval(this.trainTimer)
this.trainLoading = false
return
}
//发送请求
getData(params).then(res => {
if(res.code === 0 && res.flag){
//如果接口返回结束位标志,结束轮询
this.data = res.data
this.trainLoading = false
}
}).catch(error => {
//错误逻辑
})
}
handlePolling(demo,1000)
第二版
刚写完,经测试也无大问题,我们后端老大发话了,哎呀你这个轮询太死板了,我们的算法优化还没牵扯到整个项目,你不能固定时间请求,我们需要用科学的方法来请求。这样吧,你按照500ms,1500ms,3000ms这种方案请求,要么拿到结束状态位,要么继续往下请求。这样没经过优化的也不需要等待太长时间,也能正常展示。 好嘛,你是老大你有理,那就修改一下我们的轮询吧。因为是阶梯式请求,阶梯数也不定,所以我们采用timeout来实现。
//定义轮询时间数组
this.trainArr = [500,1500,3000]
//轮询函数
handlePolling(fn) {
if (trainTimer) {
clearInterval(this.trainTimer)
this.trainTimer = null
this.trainLoading = false
this.trainCount = 0
}
this.trainLoading = true
this.trainTimer = setTimeout(()=>{
this.trainCount++
fn();
},this.trainArr[this.trainCount])
}
demo(){
//大于轮询时间数组还无正确结果逻辑。。
if(this.trainCount >= this.trainArr.length){
clearTimeout(this.trainTimer);
this.trainLoading = false;
return
}
getData(params).then(res => {
if(res.code === 0){
clearTimeout(this.trainTimer);
this.data = res.data
if(res.flag){
this.trainCount = 0
this.trainLoading = false;
}else{
this.trainTimer = setTimeout(()=>{
this.trainCount++
this.getCode(orderInfo,grade,courseId);
},this.timeArr[this.trainCount])
}
}
}).catch(error => {
//错误逻辑
})
}
handlePolling(demo)
第三版
这时问题就出现了,哎呀,压测时间是3s,轮询数组的最后一次3000ms永远都不会走,造成拿到的结果不对。好嘛,我们在修改一下我们的轮询。
this.trainArr = [500,1500,3000]
this.trainTimer = {}
for(let i = 0;i < this.trainArr.length;i++){
this.trainTimer['timer'+i] = setTimeout(() => {
demo('timer'+i)
}, this.trainArr[i]);
}
function demo(timer) {
clearTimeout(this.trainTimers[timer]);
getData(params).then(res => {
if(res.code === 0){
this.data = res.data
if(res.flag){
this.trainLoading = false;
switch(timer){
case 'timer0':
clearTimeout(this.trainTimers['timer1']);
clearTimeout(this.trainTimers['timer2']);
break
case 'timer1':
clearTimeout(this.trainTimers['timer2']);
break
case 'timer2':
break
default:
break
}
}
if(timer === 'timer2'){
this.trainLoading = false;
}
}
}).catch(error => {
//错误逻辑
})
}
第四版
此时,我们的轮询已经经过了三版,这时前端老大过来看到你的代码,哎呦喂小伙子,你很嚣张啊,一个轮询整这么复杂?你实现的这个考虑到接口无序请求返回数据了吗?你怎么保证值是正确的?别管后台逻辑,前端就给他一个基本的轮询,他后台爱咋处理咋处理。好嘛,听到这,我们就知道又得改代码了。
//轮询函数
handlePolling(fn) {
if (trainTimer) {
clearInterval(this.trainTimer)
this.trainTimer = null
this.trainLoading = false
this.trainCount = 0
}
this.trainLoading = true
this.trainTimer = setTimeout(()=>{
this.trainCount++
fn();
},1000)
}
demo(){
//大于压测时间处理
if(this.trainCount >= 5){
clearTimeout(this.trainTimer);
this.trainLoading = false;
return
}
getData(params).then(res => {
if(res.code === 0){
clearTimeout(this.trainTimer);
this.data = res.data
if(res.flag){
this.trainCount = 0
this.trainLoading = false;
}else{
this.trainTimer = setTimeout(()=>{
this.trainCount++
this.getCode(orderInfo,grade,courseId);
},1000)
}
}
}).catch(error => {
//错误逻辑
})
}
handlePolling(demo)
兜兜转转,修修补补,一天结束。
总结
仅以本文记载今天的轮询生活。。。