setInterval在浏览器切换时加速(setInterval休眠)解决方案

3 篇文章 0 订阅

现象:使用setInterval定时器时经常会出现一个现象,从定时器页面切换到其它页面或者其它应用时在回到页面,会发现定时的动画会加速执行

原因:浏览器本着节省内存的性质,当切换到其他页面时,页面的定时器会延时执行,当切换回来的时候被延时执行的动画会一次依次执行,这样我们就会看到动画加速运动,出现错误,在轮播图之类的页面经常会发生这样的情况

解决方法一:

在这里我们需要用到以下三个知识点

  • document.onvisibilitychange :

只要页面发生变化,不管是切换到其他的页面还是把浏览器缩小,都会触发这个事件。

  • document.hidden

这个是指当页面不是当前页面时为true,否则为false

  • document.visibilityState:

这个属性有四个值,分为是:visible,hidden,prerender,unloaded

visible 表示当前网页是可见或者是部分可见的。

hidden:当前网页是不可见的

prerender 网页内容被预渲染并且用户不可见

unloaded 如果文档被卸载,那么这个值将被返回

解决setInterval在浏览器切换中的问题:

思路:如果页面是不可见的,那么我们就会清除定时器,如果页面是可见的,那么我们就重新开启定时器。

所以我们需要用document.onvisibilitychange进行监听,然后用document.visibilityState或者是document.hidden进行判断。

实际操作:

document.onvisibilitychange=function(){
  if(document.visibilityState=="visible"){
      timer=setInterval(f, 1000);
  }else{
      clearInterval(timer);
  }
}

jq中animate的解决

如果用的是jq的animate这个方法,就只需要到这个方法的前面加上stop(true,true)

$(".slidePanel").stop(true,true).animate({
	"left": -iNow*varWidth+"px",
	"speed":300
});

方法二

可以用web work来跑我们的代码,通过在worker里面开启定时器,发送message给外部,外部收到message,然后再执行操作,这样我们切换页面,但是worker不受影响,定时器就可以解决延迟了

// time worker
 
var intervalIds = {};
 
// 监听message 开始执行定时器或者销毁
self.onmessage = function(e){
    switch(e.data.command){
        case 'interval:start': // 开启定时器
            var intervalId = setInterval(function(){
                postMessage({
                    message: 'interval:tick',
                    id: e.data.id
                })
            },e.data.interval);
 
            postMessage({
                message: 'interval:started',
                id: e.data.id
            });
 
            intervalIds[e.data.id] = intervalId;
            break;
        case 'interval:clear': // 销毁
            clearInterval(intervalIds[e.data.id]);
 
            postMessage({
                message: 'interval:cleared',
                id: e.data.id
            })
 
            delete intervalIds[e.data.id];
            break;
    }
}

开启worker

var worker = new Worker('./time-worker.js');
 
var workerTimer = {
    id: 0,
    callbacks: {},
    setInterval: function(cb, interval, context) {
        this.id++;
        var id = this.id;
        this.callbacks[id] = { fn: cb, context: context };
        worker.postMessage({ command: 'interval:start', interval: interval, id: id });
        return id;
    },
 
    // 监听worker 里面的定时器发送的message 然后执行回调函数
    onMessage: function(e) {
        switch (e.data.message) {
            case 'interval:tick':
                var callback = this.callbacks[e.data.id];
                if (callback && callback.fn) callback.fn.apply(callback.context);
                break;
            case 'interval:cleared':
                delete this.callbacks[e.data.id];
                break;
        }
    },
 
    // 往worker里面发送销毁指令
    clearInterval: function(id) {
        worker.postMessage({ command: 'interval:clear', id: id });
    }
};
 
worker.onmessage = workerTimer.onMessage.bind(workerTimer);

使用实例:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>稳定版定时器</title>
</head>
<body>
<div>
    <p>Times:500ms</p>
    <p>
        开始时间(s):<span id="startTime"></span> ---- 结束时间(s):<span id="endTime"></span>
    </p>
    <p id="nums"></p>
    <button id="btn">开始</button>
</div>
<script src="worker-timer.js"></script>


<script>
    var nums = document.getElementById('nums');
    var btn = document.getElementById('btn');
    var startTime = document.getElementById('startTime');
    var endTime = document.getElementById('endTime');
    var number = 1;
    var intervalId = null;

    btn.addEventListener('click',function(e){
        if(e.target.innerHTML == '开始'){
            startTime.innerHTML = new Date().getSeconds();
            intervalId = workerTimer.setInterval(function(){
                nums.innerHTML = ++number;
            },500);
            e.target.innerHTML = '暂停';
        }else{
            endTime.innerHTML = new Date().getSeconds();
            workerTimer.clearInterval(intervalId);
            e.target.innerHTML = '开始'
        }

    },false);

</script>
</body>
</html>

参考 :

https://juejin.im/post/6844903624930230285

https://juejin.im/post/6844903608597610510

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值