定时轮询拉取数据的实现方式

4,394 阅读2分钟
「这是我参与11月更文挑战的第26天,活动详情查看:2021最后一次更文挑战

定时轮询,我们第一个会想到的就是用setInterval去实现

let milliseconds = 5000
window.timer = setInterval(()=>{ 
    fun() 
},milliseconds)

setInterval和setTimeout的区别

  • setInterval(function(){}, milliseconds) :会不停的调用函数,不会清除定时器队列
  • setTimeout(function(){}, milliseconds) 只执行函数一次,自带清除定时器的

setInterval会符合我们的业务需求,然而也需要注意一些坑,单纯的使用setInterval会导致页面卡死!其原因与JS引擎线程有关,用通俗话说就是setInterval不会清除定时器队列,每重复执行1次都会导致定时器叠加,最终卡死你的网页。但是setTimeout是自带清除定时器的,因此可以叠加使用:

window.setInterval(() => {
  setTimeout(fun, 0)
}, 30000)

setTimeout能阻止某些重复性操作

// setTimeout能阻止某些重复性操作
// 如果我们能捕获到异常,可以限定异常大于10次时,我们将不再拉取数据,并且在异常 》1 且 《10 时,我们可以适当将间隔拉大,让服务器有休息的时间。
var failed = 0; 

(function loopsiloop( interval ){
   interval = interval || 5000; // default polling to 1 second

   setTimeout(function(){
       $.ajax({
           url: 'foo.htm',
           success: function( response ){
               // do something with the response

               loopsiloop(); // recurse
           },
           error: function(){

               // only recurse while there's less than 10 failed requests.
               // otherwise the server might be down or is experiencing issues.
               if( ++failed < 10 ){

                   // give the server some breathing room by
                   // increasing the interval
                   interval = interval + 1000;
                   loopsiloop( interval );
               }
           }
       });
   }, interval);
})();

结束轮询

在需要结束轮询,或者beforeDestroy生命周期函数中销毁定时器

clearInterval(timer)

如果需要通过按钮手动结束轮询,在按钮的click事件响应函数中加上clearInterval(timer)即可

vue项目实例


<p v-if="taskStatus==='数据拉取中'">数据拉取中</p>

data () {
    return {
        taskStatus: '',
        dataTimer: null,
    }
},
created () {
    // 是否开启定时器
    if (this.taskStatus === '数据拉取中') {        
        this.dataTimer = setInterval(() => {
            setTimeout(()=>{
                // 返回一个状态,如果不是数据拉取中则停止定时器,停止拉取数据
                this.judgeStatus()
                // 返回的数据渲染到页面
                this.showData()        
            }, 0)                
        }, 5000)
    }
},
destroyed () {
    clearInterval(this.dataTimer)
},
methods: {
    judgeStatus () {
        axios.get('/judgeStatus').then((res) => {
            if (res.status === 200) {
                this.taskStatus = res.data.taskStatus
                if (res.data.taskStatus !== '数据拉取中') {
                    clearInterval(this.dataTimer)
                    this.showData()
                }
            }            
        }).catch((error) => {
            console.log(error);
        })
    }
}