【问题标题】:Changing the interval of SetInterval while it's running在运行时更改 SetInterval 的间隔
【发布时间】:2010-11-19 19:09:09
【问题描述】:

我编写了一个 javascript 函数,它使用 setInterval 每隔十分之一秒对字符串进行一定次数的迭代操作。

function timer() {
    var section = document.getElementById('txt').value;
    var len = section.length;
    var rands = new Array();

    for (i=0; i<len; i++) {
        rands.push(Math.floor(Math.random()*len));
    };

    var counter = 0
    var interval = setInterval(function() {
        var letters = section.split('');
        for (j=0; j < len; j++) {
            if (counter < rands[j]) {
                letters[j] = Math.floor(Math.random()*9);
            };
        };
        document.getElementById('txt').value = letters.join('');
        counter++

        if (counter > rands.max()) {
            clearInterval(interval);
        }
    }, 100);
};

我不想将间隔设置为特定数字,而是希望在每次运行时根据计数器对其进行更新。所以而不是:

var interval = setInterval(function() { ... }, 100);

应该是这样的:

var interval = setInterval(function() { ... }, 10*counter);

不幸的是,这没有奏效。看起来“10*counter”等于 0。

那么,如何调整匿名函数每次运行的时间间隔呢?

【问题讨论】:

    标签: javascript timer setinterval


    【解决方案1】:

    请改用setTimeout()。然后回调将负责触发下一次超时,此时您可以增加或以其他方式操纵时间。

    编辑

    这是一个通用函数,可用于为任何函数调用应用“减速”超时。

    function setDeceleratingTimeout(callback, factor, times)
    {
        var internalCallback = function(tick, counter) {
            return function() {
                if (--tick >= 0) {
                    window.setTimeout(internalCallback, ++counter * factor);
                    callback();
                }
            }
        }(times, 0);
    
        window.setTimeout(internalCallback, factor);
    };
    
    // console.log() requires firebug    
    setDeceleratingTimeout(function(){ console.log('hi'); }, 10, 10);
    setDeceleratingTimeout(function(){ console.log('bye'); }, 100, 10);
    

    【讨论】:

    • 回调是指函数的最后一行用 setTimeout(..., newInterval) 递归调用自身吗?
    • 我想这就是他的意思。我刚刚尝试过,它似乎正在工作。谢谢,伙计们!
    • 只给 9 个你好 :) --t 应该是 t-- jsfiddle.net/albertjan/by5fd
    • 如果times 太大,递归执行此操作是否会导致堆栈溢出错误?
    • 在这里很挑剔,但我得说,该代码很难阅读。如果您要使用下一行大括号,至少要体面地使用 4-8 空格缩进或永远不要超过 2 个缩进。 IMO this version 更容易阅读。还要注意将t 重命名为tick,这是我对“t”应该代表什么的最佳猜测。 t 是一个非常糟糕的变量名。
    【解决方案2】:

    我喜欢这个问题 - 启发了我的一个小计时器对象:

    window.setVariableInterval = function(callbackFunc, timing) {
      var variableInterval = {
        interval: timing,
        callback: callbackFunc,
        stopped: false,
        runLoop: function() {
          if (variableInterval.stopped) return;
          var result = variableInterval.callback.call(variableInterval);
          if (typeof result == 'number')
          {
            if (result === 0) return;
            variableInterval.interval = result;
          }
          variableInterval.loop();
        },
        stop: function() {
          this.stopped = true;
          window.clearTimeout(this.timeout);
        },
        start: function() {
          this.stopped = false;
          return this.loop();
        },
        loop: function() {
          this.timeout = window.setTimeout(this.runLoop, this.interval);
          return this;
        }
      };
    
      return variableInterval.start();
    };
    

    示例使用

    var vi = setVariableInterval(function() {
      // this is the variableInterval - so we can change/get the interval here:
      var interval = this.interval;
    
      // print it for the hell of it
      console.log(interval);
    
      // we can stop ourselves.
      if (interval>4000) this.stop();
    
      // we could return a new interval after doing something
      return interval + 100;
    }, 100);  
    
    // we can change the interval down here too
    setTimeout(function() {
      vi.interval = 3500;
    }, 1000);
    
    // or tell it to start back up in a minute
    setTimeout(function() {
      vi.interval = 100;
      vi.start();
    }, 60000);
    

    【讨论】:

    • 谢谢 - 让我朝着正确的方向前进,从事类似的工作。
    • 简单有效。谢谢!
    【解决方案3】:

    一个更简单的方法是在刷新的函数中有一个if 语句和一个控件以定期执行您的命令。在以下示例中,我每 2 秒运行一次警报,并且可以动态更改间隔 (intrv)...

    var i=1;
    var intrv=2; // << control this variable
    
    var refreshId = setInterval(function() {
      if(!(i%intrv)) {
        alert('run!');
      }
      i++;
    }, 1000);
    

    【讨论】:

    • 这也是我个人的最爱。小、简单、可扩展。
    • 我想要一个减速计时器的解决方案,它可以根据应用程序事件重置其速率;这简单而完美地满足了这一需求。谢谢。
    • 这很酷,但它也会在你不需要它的时候触发间隔......而且它有点不可读。由于这些原因,我个人更喜欢 setTimeout。
    【解决方案4】:

    你可以使用匿名函数:

    var counter = 10;
    var myFunction = function(){
        clearInterval(interval);
        counter *= 10;
        interval = setInterval(myFunction, counter);
    }
    var interval = setInterval(myFunction, counter);
    

    更新:按照 A. Wolff 的建议,使用 setTimeout 来避免使用 clearInterval

    var counter = 10;
    var myFunction = function() {
        counter *= 10;
        setTimeout(myFunction, counter);
    }
    setTimeout(myFunction, counter);
    

    【讨论】:

    • 好吧,RozzA,我的答案发布于 2011 年 9 月 16 日,user28958 发布于 2013 年 8 月 22 日,所以我会接受“代表”谢谢!
    • 为什么要使用间隔,简单的超时会更好,不需要清除它。例如:jsfiddle.net/fgs5nwgn
    • 我坚持问题的上下文。 setTimeout 当然会起作用
    • @A.Wolff 请注意,您不需要定义超时变量...它们什么也没做
    【解决方案5】:
    var counter = 15;
    var interval = setTimeout(function(){
        // your interval code here
        window.counter = dynamicValue;
        interval();
    }, counter);
    

    【讨论】:

    【解决方案6】:

    我和原始海报有同样的问题,作为解决方案这样做了。不知道这有多有效....

    interval = 5000; // initial condition
    var run = setInterval(request , interval); // start setInterval as "run"
    
        function request() { 
    
            console.log(interval); // firebug or chrome log
            clearInterval(run); // stop the setInterval()
    
             // dynamically change the run interval
            if(interval>200 ){
              interval = interval*.8;
            }else{
              interval = interval*1.2;
            }
    
            run = setInterval(request, interval); // start the setInterval()
    
        }
    

    【讨论】:

    • 我更喜欢这个答案,因为它实际上回答了 OP(和我的)问题。 setTimeout 可能会被延迟(100% cpu 使用、其他脚本等),而 setInterval 不受这些延迟的影响——这对于“实时”的东西来说要优越得多
    • 我 99% 确定您关于 setInterval 的声明是错误的 @RozzA - 它仍然会受到与任何其他 JavaScript 相同的延迟,并且几乎每个浏览器也将 setInterval 限制为 4 毫秒。你有关于这个或什么的帖子的链接吗?
    【解决方案7】:

    我也无法同步和更改我的 setIntervals 的速度,我正要发布一个问题。但我想我已经找到了办法。它当然应该改进,因为我是初学者。所以,我很乐意阅读您关于此的 cmets/remarks。

    <body onload="foo()">
    <div id="count1">0</div>
    <div id="count2">2nd counter is stopped</div>
    <button onclick="speed0()">pause</button>
    <button onclick="speedx(1)">normal speed</button>
    <button onclick="speedx(2)">speed x2</button>
    <button onclick="speedx(4)">speed x4</button>
    <button onclick="startTimer2()">Start second timer</button>
    </body>
    <script>
    var count1 = 0,
        count2 = 0,
        greenlight = new Boolean(0), //blocks 2nd counter
        speed = 1000,   //1second
        countingSpeed;
    function foo(){
        countingSpeed = setInterval(function(){
            counter1();
            counter2();
        },speed);
    }
    function counter1(){
        count1++;
        document.getElementById("count1").innerHTML=count1;
    }
    function counter2(){
        if (greenlight != false) {
            count2++;
            document.getElementById("count2").innerHTML=count2;
        }
    }
    function startTimer2(){
        //while the button hasn't been clicked, greenlight boolean is false
        //thus, the 2nd timer is blocked
        greenlight = true;
        counter2();
        //counter2() is greenlighted
    }
    
    //these functions modify the speed of the counters
    function speed0(){
        clearInterval(countingSpeed);
    }
    function speedx(a){
        clearInterval(countingSpeed);
        speed=1000/a;
        foo();
    }
    </script>
    

    如果您希望在页面加载后计数器开始增加,请在调用countingSpeed 之前将counter1()counter2() 放入foo()。否则,在执行前需要speed 毫秒。 编辑:更短的答案。

    【讨论】:

      【解决方案8】:

      简单的答案是您无法更新已创建计时器的间隔。 (只有两个函数setInterval/setTimerclearInterval/clearTimer,所以有一个timerId 你只能禁用它。)但是你可以做一些变通方法。看看this github repo

      【讨论】:

        【解决方案9】:

        这是我的做法,我使用 setTimeout:

        var timer = {
            running: false,
            iv: 5000,
            timeout: false,
            cb : function(){},
            start : function(cb,iv){
                var elm = this;
                clearInterval(this.timeout);
                this.running = true;
                if(cb) this.cb = cb;
                if(iv) this.iv = iv;
                this.timeout = setTimeout(function(){elm.execute(elm)}, this.iv);
            },
            execute : function(e){
                if(!e.running) return false;
                e.cb();
                e.start();
            },
            stop : function(){
                this.running = false;
            },
            set_interval : function(iv){
                clearInterval(this.timeout);
                this.start(false, iv);
            }
        };
        

        用法:

        timer.start(function(){
            console.debug('go');
        }, 2000);
        
        timer.set_interval(500);
        
        timer.stop();
        

        【讨论】:

        • +1,我为了我的目的稍微修改了它,所以我可以使用多个可变间隔 - jsfiddle.net/h70mzvdq
        • 还修改了set_interval 函数以不启动新的执行,除非新的间隔小于旧的。if (iv &lt; this.iv) { clearInterval(this.timeout); this.start(false, iv); } else { this.iv = iv; }
        • 我也喜欢这个解决方案,但如果计时器没有改变,除非它与上一个相差 1/2 秒,否则我更喜欢。我将set_interval 函数修改为:let round = Math.trunc( iv / 500) * 500; if (round != this.iv ) { clearInterval( this.timeout ); this.start( false, round ); }
        • 我也为我的用例修改了这个。
        【解决方案10】:

        这可以根据您的需要启动。超时是我用来保持它在小时的顶部的方法。

        我需要每小时开始一个代码块。所以这将在服务器启动时开始并每小时运行一次。基本上初始运行是在同一分钟内开始间隔。因此,在从初始化开始的一秒钟内,立即运行,然后每 5 秒运行一次。

        var interval = 1000;
        var timing =function(){
            var timer = setInterval(function(){
                console.log(interval);
                if(interval == 1000){ /*interval you dont want anymore or increment/decrement */
                    interval = 3600000; /* Increment you do want for timer */
                    clearInterval(timer);
                    timing();
                }
            },interval);
        }
        timing();
        

        或者,如果您只想在开始时发生某些事情,然后以特定的时间间隔永远发生,您可以在 setInterval 的同时调用它。例如:

        var this = function(){
         //do
        }
        setInterval(function(){
          this()
        },3600000)
        this()
        

        这里我们第一次运行,然后每小时运行一次。

        【讨论】:

          【解决方案11】:

          下面这段代码加速(acceleration > 1)或减速(acceleration setInterval函数:

          function accelerate(yourfunction, timer, refresh, acceleration) {
              var new_timer = timer / acceleration;
              var refresh_init = refresh;//save this user defined value
              if (refresh < new_timer ){//avoid reseting the interval before it has produced anything.
                  refresh = new_timer + 1 ;
              };
              var lastInter = setInterval(yourfunction, new_timer);
              console.log("timer:", new_timer);
              function stopLastInter() {
                  clearInterval(lastInter);
                  accelerate(yourfunction, new_timer, refresh_init, acceleration);
                  console.log("refresh:", refresh);
              };
              setTimeout(stopLastInter, refresh);
          }
          

          与:

          • timer: setInterval 初始值,单位 ms(递增或递减)
          • refresh:计算新值timer之前的时间。这是步长
          • acceleration:旧值和下一个timer 值之间的差距。这是步高

          【讨论】:

          • 我是盲人还是你的代码中没有factor
          • 还有,怎么阻止呢?
          • 谢谢。我更正了答案:factoracceleration 的旧名称……现在更清楚了!对此感到抱歉。关于“如何停止它”:我会将 var (continue = true) 传递给加速函数,并在加速函数中添加第一行:while (continue) {
          • 我建议停止,你返回一个清除间隔和超时的函数,当它再次调用accelerate时,你存储它返回的函数来调用它
          • 我在这里用我的更改创建了一支笔:codepen.io/Alynva/pen/vYJdwQY?editors=0011
          【解决方案12】:
          (function variableInterval() {
              //whatever needs to be done
              interval *= 2; //deal with your interval
              setTimeout(variableInterval, interval);
              //whatever needs to be done
          })();
          

          不能再短了

          【讨论】:

            【解决方案13】:

            制作新功能:

            // set Time interval
            $("3000,18000").Multitimeout();
            
            jQuery.fn.extend({
                Multitimeout: function () {
                    var res = this.selector.split(",");
                    $.each(res, function (index, val) { setTimeout(function () { 
                        //...Call function
                        temp();
                    }, val); });
                    return true;
                }
            });
            
            function temp()
            {
                alert();
            }
            

            【讨论】:

              【解决方案14】:

              这是另一种创建减速/加速间隔计时器的方法。间隔乘以一个因子,直到超过总时间。

              function setChangingInterval(callback, startInterval, factor, totalTime) {
                  let remainingTime = totalTime;
                  let interval = startInterval;
              
                  const internalTimer = () => {
                      remainingTime -= interval ;
                      interval *= factor;
                      if (remainingTime >= 0) {
                          setTimeout(internalTimer, interval);
                          callback();
                      }
                  };
                  internalTimer();
              }
              

              【讨论】:

                【解决方案15】:

                受上述内部回调的启发,我创建了一个函数来在几分钟内触发回调。如果将超时设置为 6 000、15 000、30 000、60 000 之类的间隔,它将持续同步调整间隔,以准确过渡到系统时钟的下一分钟。

                //Interval timer to trigger on even minute intervals
                function setIntervalSynced(callback, intervalMs) {
                
                    //Calculate time to next modulus timer event
                    var betterInterval = function () {
                        var d = new Date();
                        var millis = (d.getMinutes() * 60 + d.getSeconds()) * 1000 + d.getMilliseconds();
                        return intervalMs - millis % intervalMs;
                    };
                
                    //Internal callback
                    var internalCallback = function () {
                        return function () {
                            setTimeout(internalCallback, betterInterval());
                            callback();
                        }
                    }();
                
                    //Initial call to start internal callback
                    setTimeout(internalCallback, betterInterval());
                };
                

                【讨论】:

                  【解决方案16】:

                  您可以使用变量并更改变量。

                  ````setInterval([函数], [变量])```

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2013-02-12
                    • 1970-01-01
                    • 1970-01-01
                    • 2016-05-28
                    • 2019-11-11
                    • 1970-01-01
                    • 1970-01-01
                    • 2015-05-26
                    相关资源
                    最近更新 更多