记一次项目中的轮询

315 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 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)

兜兜转转,修修补补,一天结束。

总结

仅以本文记载今天的轮询生活。。。