19

对于 javascript 爱好者,

您将如何编程setTimeOut(或setInterval)句柄以按分钟触发。例如,如果是当前时间的 51 秒,则在 9 秒内触发,如果是第 14 秒,则在 46 秒内触发

谢谢

4

11 回答 11

26
var date = new Date();

setTimeout(function() {
    setInterval(myFunction, 60000);
    myFunction();
}, (60 - date.getSeconds()) * 1000);

显然这不是 100% 精确的,但对于大多数情况来说应该足够了。

于 2010-04-05T17:20:11.043 回答
10

首先,让我们确保我们知道到下一分钟还有多少时间:

var toExactMinute = 60000 - (new Date().getTime() % 60000);

现在,如果您想使用setTimeout,那么

setTimeout(yourfunction, toExactMinute);

如果你想做一个setInterval

setTimeout(function() {
    setInterval(yourFunction, 60000);
    yourFunction();
}, toExactMinute);
于 2017-10-26T13:11:27.317 回答
8
var nextTick = function() {
  return 60000 - (new Date().getTime() % 60000);
}, timerFunction = function() {
  // do stuff
  // do stuff
  // do stuff
  setTimeout(timerFunction, nextTick());
};
var timeout = setTimeout(timerFunction, nextTick());
于 2010-04-05T17:27:46.303 回答
3

起初,我使用了 Joel Potter 提出的解决方案。在大多数情况下,他的解决方案已经足够好了。但是,因为 javascript 一次只做一件事(除非您使用的是 Workers),所以第一次超时可能会迟到,所以您的第一次超时会被执行,例如。5 秒太晚了,你会在一分钟后每 5 秒获得一次间隔。

所以,这是我的实现:

function setMyFunctionInterval()
{
    var currentDateSeconds = new Date().getSeconds();
    if (currentDateSeconds == 0) {
        setInterval(myFunction, 60000);
    }
    else {
        setTimeout(function () {
            setMyFunctionInterval();
        }, (60 - currentDateSeconds) * 1000);
    }

    myFunction();
}

setMyFunctionInterval();
于 2013-02-01T10:54:56.193 回答
1
var seconds = (new Date()).getSeconds();

用作60-seconds超时时间。当然,setTimeout允许您指定毫秒,这意味着您还应该检查毫秒,但这将使您“足够接近”大多数应用程序。如果有的话,这应该会让你在几分之一秒内过冲,但过冲总比过冲好。使用这种方法,下冲将导致灾难性故障。

于 2010-04-05T17:18:02.897 回答
1
var d = new Date();
var milisecondsUntilMinuteChanges = 60000 - d.getMilliseconds() - (1000 * d.getSeconds());
于 2010-04-05T17:23:07.840 回答
1

虽然为时已晚,但我最近有类似的问题要解决,并想分享我的方法。我的问题是根据距离一分钟的距离在指定秒后运行超时,然后每分钟运行间隔函数。这就是我所做的。

假设日期是使用创建的javascript日期对象date = new Date();

  1. 让剩下的秒数达到一分钟secondsLeft = 60 - date.getSeconds();
  2. 然后设置一个超时函数在 之后运行secondsLeft,并在函数内部设置一个间隔函数以每分钟运行一次:

    setTimeout(function() {
      // perform the action **A**;
      minuteMS = 60 * 1000; // seconds * milliSeconds
      setIntervalId = setInterval(function() {
      // perform the action **A**;
     }, minuteMS);
    }, secondsLeft);
    
  3. 使用上述格式/算法,您应该能够以任何格式提供的秒数来解决类似的问题。这个想法是获得秒数和 60 秒的差异,在这些秒数之后运行超时,并在超时函数内部运行间隔函数,间隔为一分钟/或基于要求的任何内容。
于 2017-04-10T12:57:39.203 回答
0
function waitForNewMinute() {
    if (new Date().getSeconds()>1) {
        setTimeout(waitForNewMinute, 500);
    } else {
        setInterval(doMyThing,60000);
    } 
}

waitForNewMinute();
于 2010-04-05T17:33:14.030 回答
0

我使用了'(60 - date.getSeconds()) * 1000);' 数据刷新功能上的方法,虽然它有效,但随着时间的推移它“漂移”(在我改变它之前晚了 14 秒!)

由于需要立即更新数据(这显然没有发生,因为我们在同一页面上有一个时钟!),这是我想出的解决方案:

setInterval(function () {
    if(moment().format('ss') === "00"){
        console.log('we are at the 0 - update the data!');
        refresh_data();
    }
}, 1000);

这当然使用 moment.js 来查找“0”时间,它肯定会按照 OP 的要求进行 - 每分钟都会触发 - 每次!

于 2019-07-11T23:58:59.993 回答
0

我相信所有的答案都是有缺陷的。一旦启动了 setInterval,间隔时间就不能在不创建新的 setInterval 对象的情况下更改。因此,您将只使用每次迭代的初始计算时间。您可以创建新的 setInterval 对象,但是这样做成本很高。

请参阅:如何重置 setInterval 计时器?

我的建议是创建一个使用 setTimeout 的循环函数。

这是一些代码:

var duration = 5; //in minutes. This is just to control the total length
var startTime = new Date().getTime(); //must be in milliseconds

function myOnTheMinuteTimer(){
    setTimeout(function(){
        var currentTimeMS = new Date().getTime();
        var diffMs = Math.abs(startTime - currentTimeMS);
        diffMs = diffMs/1000; //take out the milliseconds
        var seconds = Math.floor(diffMs % 60);
        diffMs = diffMs/60;
        var minutes = Math.floor(diffMs % 60);
        var minutesLeft = duration - minutes;
        console.log("Time passed:", minutes + "m :" + seconds + "s");

        if(minutes <= duration){
            console.log("Timer expired.");
        } else {
            myOnTheMinuteTimer();   
        }
    }, setIntervalTimeToNextMinute());
}


//Initialize timer
myOnTheMinuteTimer();


//Get our time until the next minute
function setIntervalTimeToNextMinute(){
    var currentDateSeconds = new Date().getSeconds();
    if(currentDateSeconds == 0){
        return 60000;
    } else {
        return (60 - currentDateSeconds) * 1000;
    }
}

我的用例是会话超时:

startTime - 允许我通过任何毫秒的时间。这样我可以避免页面加载的失误。假设用户在某个时间登录。我捕获了那个时间,然后将它传递给初始函数,它将调整回按分钟计算。

持续时间- 我使用持续时间检查进行超时设置。如果应用程序有 20 分钟的超时,那么我需要将用户路由到登录屏幕。

可选 - 您可以添加更多变体。假设您希望给用户 2 分钟的警告,告知他们将被注销。只需添加条件 an else if 2 分钟。

希望有帮助!快乐编码!

于 2019-11-15T15:35:02.637 回答
0

这实际上可以通过与 结合相当简单地setTimeout完成setInterval。我将首先以长格式演示如何做到这一点,然后在下面提供一个速记单行函数,它将完成同样的事情。

function setEmomInterval(expr, ...rest) {
  setTimeout(function() {
    expr(...rest);
    setInterval(expr, 60000, ...rest);
  }, 60000 - new Date().getTime() % (60 * 1000));
}

setEmomInterval(() => console.log(`The time is now ${new Date().getHours()}:${new Date().getMinutes()}`));

这具有额外的好处,不仅精确到秒,而且实际上精确到毫秒,减去由于计算时间导致的任何最小延迟。

作为单线,它看起来像这样:

const setEmomInterval = (expr, ...rest) => setTimeout(() => (expr(...rest), setInterval(expr, 60000, ...rest)), 60000 - new Date().getTime() % (60 * 1000));

setEmomInterval(() => console.log(`The time is now ${new Date().getHours()}:${new Date().getMinutes()}`));

如前所述,由于计算时间中所谓的“漂移”而存在一些延迟。要解决此问题,如果您需要最准确的时间,请使用Dan Kaplun 的无漂移库(GitHub 上的 @dbkaplun

于 2021-05-29T21:46:47.047 回答