Modifica dell'intervallo di SetInterval mentre è in esecuzione


161

Ho scritto una funzione javascript che utilizza setInterval per manipolare una stringa ogni decimo di secondo per un certo numero di iterazioni.

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

Invece di avere l'intervallo impostato su un numero specifico, vorrei aggiornarlo ogni volta che viene eseguito, basato su un contatore. Quindi invece di:

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

Sarebbe qualcosa del tipo:

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

Sfortunatamente, non ha funzionato. Sembra che "10 * counter" sia uguale a 0.

Quindi, come posso regolare l'intervallo ogni volta che viene eseguita la funzione anonima?

Risposte:


107

Usa setTimeout()invece. Il callback sarebbe quindi responsabile per l'attivazione del timeout successivo, a quel punto è possibile aumentare o altrimenti manipolare i tempi.

MODIFICARE

Ecco una funzione generica che puoi usare per applicare un timeout "in rallentamento" per QUALSIASI chiamata di funzione.

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

1
Per callback, intendi l'ultima riga della funzione che si chiama ricorsivamente con un setTimeout (..., newInterval)?
Marc,

1
Immagino sia quello che intendeva dire. L'ho appena provato e sembra funzionare. Grazie ragazzi!
Joe Di Stefano,

2
dà solo 9 ciao :) --tprobabilmente dovrebbe essere t-- jsfiddle.net/albertjan/by5fd
albertjan

1
In questo modo ricorsivamente non corri il rischio di ottenere un errore di overflow dello stack se timesè troppo grande?
André C. Andersen

4
Essendo nitido qui, ma devo dire che quel codice è piuttosto difficile da leggere. Se utilizzerai le parentesi graffe della riga successiva, almeno avrai la decenza di utilizzare il rientro di 4-8 spazi o di non andare mai oltre i 2 rientri. IMO questa versione è molto più facile da leggere. Prendi anche nota della ridenominazione di tto tick, che era la mia ipotesi migliore su qualunque cosa "t" dovrebbe rappresentare. tè un nome variabile piuttosto male.
Braden Best

124

È possibile utilizzare una funzione anonima:

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

AGGIORNAMENTO: Come suggerito da A. Wolff, usare setTimeoutper evitare la necessità clearInterval.

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

5
Bene RozzA, la mia risposta è stata pubblicata il 16 settembre 11 e l'utente 28958 il 22 agosto 13, quindi prenderò il "rappresentante" grazie!
Nick,

12
Perché stai usando un intervallo, un semplice timeout sarebbe meglio senza la necessità di cancellarlo. ad es .: jsfiddle.net/fgs5nwgn
A. Wolff l'

4
Mi attenevo al contesto della domanda. setTimeout funzionerà ovviamente
nick

24

Mi piace questa domanda - ho ispirato un piccolo oggetto timer in me:

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

Esempio di utilizzo

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

4
Grazie: mettimi nella giusta direzione per qualcosa di simile a cui sto lavorando.
Colonnello Sponsz,

Semplice ed efficace Grazie!
Giullare

18

Ho avuto la stessa domanda del poster originale, come soluzione. Non sono sicuro di quanto sia efficiente ....

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

    }

mi piace meglio questa risposta perché in realtà risponde alla domanda OP (e alla mia). setTimeout è soggetto a ritardi (del 100% di utilizzo della CPU, altri script, ecc.) in cui setInterval NON è influenzato da tali ritardi - il che lo rende di gran lunga superiore per roba 'in tempo reale'
RozzA

8
Sono sicuro al 99% che la tua affermazione setIntervalsia errata @RozzA - È ancora soggetta agli stessi ritardi di qualsiasi altro JavaScript e quasi tutti i browser bloccano setInterval su 4ms. Hai un link a un post su questo o qualcosa del genere?
gnarf,

9

Questo è il mio modo di fare questo, io uso 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);
    }
};

Uso:

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

timer.set_interval(500);

timer.stop();

+1, l'ho modificato leggermente per i miei scopi in modo da poter utilizzare più intervalli variabili - jsfiddle.net/h70mzvdq
Dallas

Modificata anche la set_intervalfunzione per NON dare il via a una nuova esecuzione a meno che il nuovo intervallo non sia inferiore a quello precedente.if (iv < this.iv) { clearInterval(this.timeout); this.start(false, iv); } else { this.iv = iv; }
Dallas,

9

Un modo molto più semplice sarebbe avere ifun'istruzione nella funzione aggiornata e un controllo per eseguire il comando a intervalli di tempo regolari. Nel seguente esempio, eseguo un avviso ogni 2 secondi e l'intervallo ( intrv) può essere modificato in modo dinamico ...

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

var refreshId = setInterval(function() {
  if(!(i%intrv)) {
    alert('run!');
  }
  i++;
}, 1000);

Anche questo è il mio preferito. piccolo, semplice, estensibile.
guy mograbi,

Volevo una soluzione di un timer in decelerazione che potesse essere ripristinato in base agli eventi dell'applicazione; questo ha incontrato quel bisogno semplicemente e perfettamente. Grazie.
Andrew Brown,

È bello, ma genera anche intervalli in momenti in cui non ne hai bisogno ... inoltre è un po 'illeggibile. Per questi motivi preferirei impostare personalmente TimeTime.
Kokodoko,

4

Questo può essere avviato nel modo desiderato. il timeout è il metodo che ho usato per mantenerlo in cima all'ora.

Avevo bisogno che ogni ora iniziasse un blocco di codice ogni ora. Quindi questo dovrebbe iniziare all'avvio del server ed eseguire l'intervallo ogni ora. Fondamentalmente la corsa iniziale è iniziare l'intervallo entro lo stesso minuto. Quindi, in un secondo da init, esegui immediatamente e poi ogni 5 secondi.

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

In alternativa, se volevi che succedesse qualcosa all'inizio e poi per sempre a un intervallo specifico, puoi semplicemente chiamarlo contemporaneamente a setInterval. Per esempio:

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

Qui abbiamo questa corsa la prima volta e poi ogni ora.


3

La risposta è semplice che non possibile aggiornare un intervallo di timer già creato . (Ci sono solo due funzioni setInterval/setTimere clearInterval/clearTimer, quindi avere un timerIdpuoi solo disattivarlo.) Ma puoi fare delle soluzioni alternative. Dai un'occhiata a questo repository github .


2

Non sono riuscito a sincronizzare e modificare la velocità anche con il mio setIntervals e stavo per pubblicare una domanda. Ma penso di aver trovato un modo. Dovrebbe sicuramente essere migliorato perché sono un principiante. Quindi, sarei lieto di leggere i tuoi commenti / osservazioni su questo.

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

Se si desidera che i contatori iniziano ad aumentare una volta che la pagina viene caricata, messa counter1()e counter2()nella foo()prima countingSpeedsi chiama. Altrimenti, ci vogliono speedmillisecondi prima dell'esecuzione. EDIT: risposta più breve.


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

non può essere più breve


1

Sono un principiante in JavaScript e non ho trovato alcun aiuto nelle risposte precedenti (ma molte buone idee).
Questo pezzo di codice sotto accelera (accelerazione> 1) o decelera (accelerazione <1). Spero che possa aiutare alcune persone:

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

Con :

  • timer: il valore iniziale setInterval in ms (crescente o decrescente)
  • refresh: il tempo prima che timervenga calcolato un nuovo valore di . Questa è la lunghezza del passo
  • factor: il divario tra il vecchio e il prossimo timervalore. Questa è l' altezza del gradino

1

Crea una nuova funzione:

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

1

Ecco un altro modo per creare un timer intervallo di decelerazione / accelerazione. L'intervallo viene moltiplicato per un fattore fino a quando non viene superato un tempo totale.

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

0
var counter = 15;
var interval = setTimeout(function(){
    // your interval code here
    window.counter = dynamicValue;
    interval();
}, counter);

dammi errore: Uncaught TypeError: interval is not a functionma questo ha funzionato: jsfiddle.net/fgs5nwgn
Nabi KAZ

0

Ispirato dal callback interno sopra, ho creato una funzione per attivare un callback in frazioni di minuti. Se il timeout è impostato su intervalli come 6.000, 15.000, 30.000, 60.000, adatterà continuamente gli intervalli sincronizzati all'esatta transizione al minuto successivo dell'orologio di sistema.

//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());
};
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.