Skip to content

Latest commit

 

History

History
84 lines (66 loc) · 2.65 KB

修正定时器的执行频率问题.md

File metadata and controls

84 lines (66 loc) · 2.65 KB

修正定时器的执行频率问题

需求描述

实现一个5分钟的倒计时功能。

问题原因

当浏览器被最小化或者对应的选项页面被隐藏时浏览器都会为了节省CPU资源降低定时器的执行频率。 当使用 setTimeout 递归调用实现的倒计时功能问题更加明显(因为单次定时器的时间时时间间隔再加上定时任务本身所需要的时间,这样随着执行会越来越不准)。

解决方案一

在不需要严格的定时同步情况下,我们可以利用浏览器的 visibilitychange 事件监听当前页面的激活情况,当页面处于不可见状态时就暂停定时器的执行,当页面被重新激活时就再次执行定时器。

// JavaScript
function countDonw(timestamp, callback) {
    var timestamp = timestamp;
    return function() {
        if (timestamp >= 0) {
            var m = ~~(timestamp / 60);
            var s = ~~(timestamp % 60);
            callback && callback(m, s);
            timestamp--;
        }
    }
}

// 创建5分钟的倒计时
var countDown5Minute = countDonw(5 * 60, function(m, s) {
    document.body.innerHTML = m + '分' + s + '秒';
});

// 执行倒计时
var intervalId = setInterval(countDown5Minute, 1000);

// 基于页面状态控制定时器执行
document.addEventListener('visibilitychange', function(e) {
    if (document.hidden) {
        clearInterval(intervalId);
        intervalId = null;
    } else {
        intervalId = setInterval(countDown5Minute, 1000);
    }
});

解决方案二

如果需要严格的与本地时间同步,那么可以在每秒的定时间隔执行中读取本地的时间,这样哪怕定时器变慢了,只要定时器执行了就会立即同步(跳转)到本地的倒计时时间。

// JavaScript
function localCountDonw(timestamp, callback) {
    // 基于本地时间增加5分钟
    var timestamp = (~~(new Date() + 1 / 1000)) + timestamp;
    return function() {
        // 获取当前时刻的本地时间
        var curTimeStamp = ~~(new Date() + 1 / 1000);
        // 计算当前本地时间与要倒计时的时间戳之差。
        var diffTime = timestamp - curTimeStamp;
        if (diffTime >= 0) {
            var m = ~~(diffTime / 60);
            var s = ~~(diffTime % 60);
            callback && callback(m, s);
            timestamp--;
        }
    }
}

// 创建5分钟的倒计时
var countDown5Minute = localCountDonw(5 * 60, function(m, s) {
    document.body.innerHTML = m + '分' + s + '秒';
});

// 执行倒计时
var intervalId = setInterval(countDown5Minute, 1000);

解决方案三

单次定时器(setTimeout) 结合本地时间进行修正。