Ändern des Intervalls von SetInterval während der Ausführung

161

Ich habe eine Javascript-Funktion geschrieben, die setInterval verwendet, um eine Zeichenfolge alle Zehntelsekunden für eine bestimmte Anzahl von Iterationen zu bearbeiten.

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);
};

Anstatt das Intervall auf eine bestimmte Zahl einzustellen, möchte ich es jedes Mal aktualisieren, wenn es ausgeführt wird, basierend auf einem Zähler. Also statt:

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

Es wäre so etwas wie:

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

Das hat leider nicht funktioniert. Es schien, als ob "10 * Zähler" gleich 0 ist.

Wie kann ich das Intervall jedes Mal anpassen, wenn die anonyme Funktion ausgeführt wird?

Joe Di Stefano
quelle

Antworten:

107

Verwenden Sie setTimeout()stattdessen. Der Rückruf ist dann für das Auslösen des nächsten Timeouts verantwortlich. An diesem Punkt können Sie das Timing erhöhen oder auf andere Weise manipulieren.

BEARBEITEN

Hier ist eine allgemeine Funktion, mit der Sie ein "Verzögerungszeit" -Zeitlimit für JEDEN Funktionsaufruf anwenden können.

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);
Peter Bailey
quelle
1
Meinen Sie mit Rückruf, dass sich die letzte Zeile der Funktion rekursiv mit einem setTimeout (..., newInterval) aufruft?
Marc
1
Ich nehme an, das hat er gemeint. Ich habe es gerade versucht und es scheint zu funktionieren. Danke Leute!
Joe Di Stefano
2
gibt nur 9 hi's :) --tsollte wohl t-- jsfiddle.net/albertjan/by5fd sein
albertjan
1
Wenn Sie dies rekursiv tun, laufen Sie nicht Gefahr, einen Stapelüberlauffehler zu erhalten, wenn dieser timeszu groß ist?
André C. Andersen
4
Hier pingelig zu sein, aber ich muss sagen, dieser Code ist ziemlich schwer zu lesen. Wenn Sie Klammern der nächsten Zeile verwenden möchten, sollten Sie mindestens den Anstand haben, entweder Einrückungen mit 4 bis 8 Leerzeichen zu verwenden oder niemals über 2 Einrückungen hinauszugehen. IMO ist diese Version viel einfacher zu lesen. Beachten Sie auch die Umbenennung von tin tick, was meine beste Vermutung war, wofür "t" stehen soll. tist ein ziemlich schlechter Variablenname.
Braden Best
124

Sie könnten eine anonyme Funktion verwenden:

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

UPDATE: Verwenden Sie setTimeout, wie von A. Wolff vorgeschlagen, um die Notwendigkeit zu vermeiden clearInterval.

var counter = 10;
var myFunction = function() {
    counter *= 10;
    setTimeout(myFunction, counter);
}
setTimeout(myFunction, counter);
Nick
quelle
5
Nun, RozzA, meine Antwort wurde am 16. September 11 und die von user28958 am 22. August 13 veröffentlicht, also werde ich mich bei dem "Repräsentanten" bedanken!
Nick
12
Warum verwenden Sie ein Intervall? Ein einfaches Timeout wäre besser, ohne es löschen zu müssen. zB: jsfiddle.net/fgs5nwgn
A. Wolff
4
Ich habe mich an den Kontext der Frage gehalten. setTimeout wird natürlich funktionieren
Nick
24

Ich mag diese Frage - inspiriert ein kleines Timer-Objekt in mir:

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();
};

Beispiel Verwendung

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);
Zwerg
quelle
4
Danke - mach mich auf den Weg in die richtige Richtung für etwas Ähnliches, an dem ich arbeite.
Oberst Sponsz
Einfach und effektiv. Vielen Dank!
Jester
18

Ich hatte die gleiche Frage wie das Originalplakat, tat dies als Lösung. Ich bin mir nicht sicher, wie effizient das ist ...

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()

    }
user28958
quelle
Ich mag diese Antwort besser, weil sie tatsächlich die OP (und meine) Frage beantwortet. setTimeout kann verzögert werden (durch 100% CPU-Nutzung, andere Skripte usw.), wenn setInterval NICHT von diesen Verzögerungen betroffen ist - was es für 'Echtzeit'-Sachen weit überlegen macht
RozzA
8
Ich bin mir zu 99% sicher, dass Ihre Behauptung setIntervalfalsch ist @RozzA - Es unterliegt immer noch den gleichen Verzögerungen wie bei jedem anderen JavaScript, und fast jeder Browser klemmt setInterval auch auf 4 ms. Hast du einen Link zu einem Beitrag darüber oder so?
Gnarf
9

Dies ist meine Art, dies zu tun, ich benutze 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);
    }
};

Verwendung:

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

timer.set_interval(500);

timer.stop();
Jaapze
quelle
+1, ich habe es für meine Zwecke leicht modifiziert, damit ich mehrere variable Intervalle verwenden kann - jsfiddle.net/h70mzvdq
Dallas
Außerdem wurde die set_intervalFunktion so geändert , dass KEINE neue Ausführung gestartet wird, es sei denn, das neue Intervall ist kleiner als das alte.if (iv < this.iv) { clearInterval(this.timeout); this.start(false, iv); } else { this.iv = iv; }
Dallas,
9

Ein viel einfacherer Weg wäre, eine ifAnweisung in der aktualisierten Funktion und ein Steuerelement zu haben, um Ihren Befehl in regelmäßigen Zeitintervallen auszuführen. Im folgenden Beispiel führe ich alle 2 Sekunden eine Warnung aus und das Intervall ( intrv) kann dynamisch geändert werden ...

var i=1;
var intrv=2; // << control this variable

var refreshId = setInterval(function() {
  if(!(i%intrv)) {
    alert('run!');
  }
  i++;
}, 1000);
Kiril Cvetkov
quelle
Dies ist auch mein persönlicher Favorit. klein, einfach, erweiterbar.
Kerl Mograbi
Ich wollte eine Lösung für einen Verzögerungszeitgeber, dessen Rate basierend auf Anwendungsereignissen zurückgesetzt werden kann. Dies erfüllte dieses Bedürfnis einfach und perfekt. Danke dir.
Andrew Brown
Es ist cool, aber es löst auch Intervalle in Momenten aus, in denen Sie es nicht brauchen ... es ist auch ein bisschen unlesbar. Aus diesen Gründen würde ich setTimeout persönlich bevorzugen.
Kokodoko
4

Dies kann beliebig initiiert werden. Timeout ist die Methode, mit der ich es auf dem neuesten Stand gehalten habe.

Ich musste jede Stunde einen Codeblock zu jeder vollen Stunde beginnen. Dies würde also beim Serverstart beginnen und das Intervall stündlich ausführen. Grundsätzlich besteht der erste Lauf darin, das Intervall innerhalb derselben Minute zu beginnen. Führen Sie also in einer Sekunde nach Init sofort alle 5 Sekunden aus.

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();

Wenn Sie alternativ möchten, dass beim Start und dann für immer in einem bestimmten Intervall etwas passiert, können Sie es auch gleichzeitig mit dem setInterval aufrufen. Beispielsweise:

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

Hier haben wir diesen Lauf das erste Mal und dann jede Stunde.

Dgerena
quelle
3

Eine einfache Antwort ist, dass Sie ein Intervall des bereits erstellten Timers nicht aktualisieren können . (Es gibt nur zwei Funktionen, setInterval/setTimerund clearInterval/clearTimerwenn timerIdSie eine haben , können Sie sie nur deaktivieren.) Sie können jedoch einige Problemumgehungen vornehmen. Schauen Sie sich dieses Github-Repo an .

vbarbarosh
quelle
2

Ich konnte meine setIntervals auch nicht synchronisieren und die Geschwindigkeit ändern und wollte gerade eine Frage stellen. Aber ich glaube ich habe einen Weg gefunden. Es sollte auf jeden Fall verbessert werden, weil ich ein Anfänger bin. Daher würde ich gerne Ihre Kommentare / Bemerkungen dazu lesen.

<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>

Wenn Sie möchten, dass die Zähler nach dem Laden der Seite ansteigen, wird put counter1()and counter2()in foo()before countingSpeedaufgerufen. Andernfalls dauert die speedAusführung Millisekunden. EDIT: Kürzere Antwort.

BEAGMB
quelle
2
(function variableInterval() {
    //whatever needs to be done
    interval *= 2; //deal with your interval
    setTimeout(variableInterval, interval);
    //whatever needs to be done
})();

kann nicht kürzer werden

Mikakun
quelle
1

Ich bin ein Anfänger in Javascript und habe in den vorherigen Antworten keine Hilfe gefunden (aber viele gute Ideen).
Dieser Code unten beschleunigt (Beschleunigung> 1) oder verlangsamt (Beschleunigung <1). Ich hoffe es könnte einigen Leuten helfen:

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);
}

Mit:

  • timer: der setInterval-Anfangswert in ms (ansteigend oder abnehmend)
  • refresh: Die Zeit, bevor ein neuer Wert von timerberechnet wird. Dies ist die Schrittlänge
  • factor: die Lücke zwischen dem alten und dem nächsten timerWert. Dies ist die Stufenhöhe
mquantin
quelle
1

Neue Funktion erstellen:

// 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();
}
Doshi schlagen
quelle
1

Hier ist eine weitere Möglichkeit, einen Verzögerungs- / Beschleunigungsintervall-Timer zu erstellen. Das Intervall wird mit einem Faktor multipliziert, bis eine Gesamtzeit überschritten wird.

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();
}
jo_va
quelle
0
var counter = 15;
var interval = setTimeout(function(){
    // your interval code here
    window.counter = dynamicValue;
    interval();
}, counter);
Hamidreza
quelle
gib mir Fehler: Uncaught TypeError: interval is not a functionaber das hat funktioniert: jsfiddle.net/fgs5nwgn
Nabi KAZ
0

Inspiriert von dem internen Rückruf oben, habe ich eine Funktion erstellt, um einen Rückruf in Bruchteilen von Minuten auszulösen. Wenn das Zeitlimit auf Intervalle wie 6 000, 15 000, 30 000, 60 000 eingestellt ist, werden die Intervalle kontinuierlich synchron an den genauen Übergang zur nächsten Minute Ihrer Systemuhr angepasst.

//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());
};
Flodis
quelle