关于页面定时轮询导致的三个坑

1,007 阅读2分钟

由于业务中查询页面接口定时轮询,使用方法不对的话,可能导致页面很卡,或者因为接口返回时序不符合预期,导致渲染结果错误,如何避免这些坑呢?

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时间很长,也就是说很多接口都处于等待状态。

image.png

后来才知道,用户打开了很多个页面,其中有好几个页面都在处于定时请求接口。而浏览器对目标服务器最多能建立的请求连接是6个。超过6个就会处于排队状态了

image.png

这里能做的优化则是,在系统页面跳转的时候,尽可能在当前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;