【问题标题】:setInterval By the minute On the minutesetInterval 按分钟 按分钟
【发布时间】:2011-02-04 12:06:34
【问题描述】:

致 javascript 爱好者,

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

谢谢

【问题讨论】:

  • 澄清:问题是 javascript 开发人员展示使用 settimeout setinterval 内置函数的创造性方法 --

标签: javascript settimeout


【解决方案1】:
var date = new Date();

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

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

【讨论】:

  • 假设处理需要一段时间,如果 myFunction 花费的时间超过 0 时间,这将很快结束,它会。
  • 每次都需要重新计算。
  • 你不需要每次都重新计算。我同意应该在间隔之后调用myFunction(我进行了编辑以更正),但是由于setInterval 而造成的延迟将是微不足道的。
  • 我认为如果“myFunction”需要一段时间来计算,javascript 中的 setInterval 会自行修复。
  • @M28,由于myFunction 是一个参考,因此在60 秒用完之前不需要计算,此时应在计算myfunction() 之前设置下一个间隔。
【解决方案2】:

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

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

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

setTimeout(yourfunction, toExactMinute);

如果你想做一个setInterval:

setTimeout(function() {
    setInterval(yourFunction, 60000);
    yourFunction();
}, toExactMinute);

【讨论】:

    【解决方案3】:
    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());
    

    【讨论】:

    • FYI 模数 % 运算符可直接用于 Date 对象,将您的代码缩短为 60000 - (new Date() % 60000)
    • 正是我的原因,我问了q? :)
    【解决方案4】:

    起初,我使用了 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();
    

    【讨论】:

      【解决方案5】:
      var seconds = (new Date()).getSeconds();
      

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

      【讨论】:

        【解决方案6】:
        var d = new Date();
        var milisecondsUntilMinuteChanges = 60000 - d.getMilliseconds() - (1000 * d.getSeconds());
        

        【讨论】:

          【解决方案7】:

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

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

          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 的差异,在这些秒之后运行超时,并在超时函数内部运行间隔函数,间隔为一分钟/或根据要求的任何值。

          【讨论】:

            【解决方案8】:
            function waitForNewMinute() {
                if (new Date().getSeconds()>1) {
                    setTimeout(waitForNewMinute, 500);
                } else {
                    setInterval(doMyThing,60000);
                } 
            }
            
            waitForNewMinute();
            

            【讨论】:

              【解决方案9】:

              我使用了'(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 的要求执行 - 每次都会触发!

              【讨论】:

                【解决方案10】:

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

                见:How do I reset the setInterval timer?

                我的建议是创建一个使用 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 分钟的警告,告知他们将被注销。只需将条件添加到 else if 2 分钟。

                希望对您有所帮助!编码愉快!

                【讨论】:

                  【解决方案11】:

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

                  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 的 driftless 库(GitHub 上的@dbkaplun)。

                  【讨论】:

                    猜你喜欢
                    • 2015-06-13
                    • 2015-05-07
                    • 1970-01-01
                    • 1970-01-01
                    • 2021-09-30
                    • 1970-01-01
                    • 2020-01-28
                    • 2020-03-03
                    • 1970-01-01
                    相关资源
                    最近更新 更多