有没有一种优雅的方式来实现时钟更新事件?

7
据我所知(虽然了解相对较少),目前没有本地事件会在例如秒针滴答声时发出。我能想到的最好方法是反复检查一个Date对象(例如每333毫秒;更短的间隔可以获得更高的精度,但也更加资源密集)。不知为何,如果我反复使用同一个Date对象,时间就不会更新,而
Date.prototype.getSeconds()

typeof为'number'时,日志显示为'NaN'。

    function clock(interval) {
    var d = new Date();
    var secondsOld = d.getSeconds();
    d = null;

    setInterval(function() {
        var d = new Date();
        var secondsNew = d.getSeconds();
        if ( secondsNew !== secondsOld ) {
            secondsOld = secondsNew;
            // trigger something
            console.log(secondsOld);
        }
        d = null;
    }, interval);
}

你需要知道系统日期吗?如果不需要,你可以将时间间隔设置为1000毫秒并计算经过的秒数。 - Djizeus
2
为什么你想要在系统时间的精确变化时触发某些操作?这似乎是一个相当任意的“滴答声”来计时,难道它比仅在1000毫秒(1秒)间隔上触发函数更好吗? - Pudge601
2
如果您想每秒收到通知,为什么不使用1000毫秒的间隔呢? - source.rar
作为一则旁注:typeof NaN === 'number' - Teemu
3
我不确定为什么这需要与系统时钟的滴答声完全同步。只需使用“setInterval”每秒运行函数,您肯定会得到完全相同的结果。 - Pudge601
显示剩余2条评论
2个回答

6

您说得没错,没有本地时钟滴答事件。我会尝试使用setTimeout()Date.now()来解决这个问题,这是一个性能优异而且精确的方法。

创建一个递归函数,在每秒钟调用setTimeout()。要保持精确,将超时设置为从该函数调用开始的下一个精确秒数的持续时间。以下是一个示例:

// milliseconds per second
var SECOND = 1000;

function bindClockTick(callback) {
    function tick() {
        var now = Date.now();

        callback(now);

        setTimeout(tick, SECOND - (now % SECOND));
    }

    tick();
}

bindClockTick(function(ms) {
    console.log('tick! milliseconds: '+ ms);
});

这里使用Date.now()而不是创建Date类的新实例。

这是一个JSFiddle,可以测试精度。 演示使用new Date()轻松显示当前时间,但只使用毫秒也可以完成。


0

我不确定为什么您想要与精确的秒数更改同步;但是,以下是我会这样做的方法:

function clock() {
    var startMs = Date.now(),
        startSecs = Math.floor(startMs / 1000),
        firstOffset = 1000 - startMs % 1000;

    function tick () {
        var ms = Date.now(),
            secs = Math.floor(ms / 1000),
            dSecs = secs - startSecs;
        console.log(dSecs);
    }

    setTimeout(function () {
        tick();
        setInterval(tick, 1000);
    }, firstOffset);
    tick();
}
clock();

以下是发生的事情:

  1. 我使用 Date.now() 获取当前时间(以毫秒为单位)
  2. 我计算出距离下一秒滴答声还有多少毫秒(firstOffset
  3. 我将初始的 setTimeout 设置为这个偏移量,确保它会在下一个秒滴答声触发。
  4. 现在我们已经与秒滴答声同步,setInterval 每 1000 毫秒将继续每秒更新一次。

对于 Date.now() 的加一操作,这已经解决了一半的问题,但剩下的是我提到的琢磨。然而,似乎没有其他方法来创建事件发射器,除了使用 setInterval 或类似的方法。 - suissidle
据我所知,目前没有这样的发射器;然而,上述代码应该提供相同的功能。 - Robert Messerle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接