每分钟调用一次函数

call function on the minute every minute

本文关键字:一次 函数 调用 每分钟      更新时间:2024-05-31

我认为我编写的每分钟调用一个函数的代码是有缺陷的,因为它在一段时间内很好,但自页面加载以来,每小时往往会滞后约 15 秒。老实说,我无法弄清楚导致滞后的原因,也许是执行函数所需的时间,小失误都加起来累积。有没有办法自动纠正函数中的失误。或者,也许有人知道实现分钟函数调用的更好方法。任何帮助或想法非常感谢。谢谢。

var now = new Date();
var delay = 60 * 1000; // 1 min in msec
var start = delay - (now.getSeconds()) * 1000 + now.getMilliseconds();
setTimeout(function setTimer() {
  onTheMinFunc();
    setTimeout(setTimer, delay);
}, start);     

首先,DOM Timers API 不保证准确性。我引用:

此 API 不保证计时器将完全按计划运行。由于 CPU 负载、其他任务等导致的延迟是意料之中的。

其次,由于执行onTheMinFunc()的时间,每轮都有延迟(您仅在完成后设置超时(。

因此,假设onTheMinFunc执行需要半秒 - 您每分钟都有半秒的延迟并且它会累积 - 仅 10 分钟后它会滞后很多。(注意,函数通常不应超过 15 毫秒才能执行,以避免明显的延迟(

尝试:

setInterval(onTheMinFunc, delay);

它仍然不会很准确。您可以以更短的间隔轮询并跟踪日期变量 - 但同样 - 不能保证。

您可能想要的是setInterval

setInterval(onTheMinFunc, delay);  

照原样,使用 setTimeout 的代码意味着在下一个开始之前,执行onTheMinFunc所需的时间会添加到延迟中,因此随着时间的推移,这种额外的延迟将加起来。

使用 setInterval 会更准确,因为延迟是在调用执行函数之间,而不是仅在函数完成后才启动计时器。

计时器和javascript时间不是很准确,我认为确保一个函数随着时间的推移每整分钟执行一次的唯一方法是每秒检查一次秒数。

setInterval(function() {
    if ( new Date().getSeconds() === 0 ) onTheMinFunc();
},1000);

小提琴

我认为你想要更接近这个的东西:

function setNextMinute() {
    // figure out how much time remains before the end of the current minute
    var d = new Date().getTime()%60000;
    //set a timeout to occur when that expires.
    setTimeout(function () {
    // recalculate a new timeout so that your timer doesn't lag over time.
        doWhateverYouWantToHere();
        // note that calling doWhateverYouWantToHere() will 
        // not offset the next minute, since it is recalculated in setNextMinute()
        setNextMinute();
    },60000-d);
}
setNextMinute();

警告:我没有彻底测试时间。 但它似乎在 1 秒间隔和 1 分钟间隔内工作得足够好。

这样做的优点是不会每秒重新计算,也不仅仅是从当前时间启动 60 秒计时器。

以下是对代码的轻微修改:

function everyMinute(fn) {
   arguments[1] && fn();
   var now = new Date();
   var delay = 60 * 1000 - (now.getSeconds()) * 1000 + now.getMilliseconds();
   setTimeout(function(){
     everyMinute(fn, true);
   }, start);
}
everyMinute(onTheMinFunc);

它每次都会重新计算等待下一分钟的毫秒数,以便尽可能精确到分钟顶部。

当前接受的答案可能矫枉过正

每秒(永远(执行if ( new Date().getSeconds() === 0 ) onTheMinFunc();似乎不是一个好主意。

我不会根据以下命题进行基准测试,没有必要。

蛛丝马迹

  1. 使用任何必要的逻辑来计算开始时刻
  2. 在开始时刻

    1. 使用setInterval重新执行
    2. 执行第一个调用

      • 请注意setInterval称为"尽快"以避免时间流逝。

如果你想要那个new Date().getSeconds() === 0

var id = setInterval(function() {
    if ( new Date().getSeconds() === 0 ) {
        setInterval(onTheMinFunc, delay);
        onTheMinFunc();
        clearInterval(id);
    }
},1000);

或者,您可以使用自己的逻辑:

var now = new Date();
var delay = 60 * 1000; // 1 min in msec
var start = delay - (now.getSeconds()) * 1000 + now.getMilliseconds();
setTimeout(function() {
  setInterval(onTheMinFunc, delay);
  onTheMinFunc();
}, start);

请检查在 jsfiddle 上工作的两个示例

第二个(示例 B(似乎更准确。