177 votes

Modification de l'intervalle de SetInterval pendant qu'il est en cours d'exécution

J'ai écrit une fonction javascript qui utilise setInterval pour manipuler une chaîne de caractères tous les dixièmes de seconde pendant un certain nombre d'itérations.

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

Au lieu de fixer l'intervalle à un nombre spécifique, je voudrais le mettre à jour à chaque fois qu'il s'exécute, sur la base d'un compteur. Donc, au lieu de :

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

Ce serait quelque chose comme :

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

Malheureusement, cela n'a pas fonctionné. Il semble que "10*compteur" soit égal à 0.

Alors, comment puis-je ajuster l'intervalle à chaque fois que la fonction anonyme s'exécute ?

139voto

nick Points 170

Vous pourriez utiliser une fonction anonyme :

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

UPDATE : Comme suggéré par A. Wolff, utilisez setTimeout pour éviter la nécessité de clearInterval .

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

5 votes

Eh bien RozzA, ma réponse a été postée le 16 septembre 11 et celle de l'utilisateur 28958 le 22 août 13, donc je vais prendre le "rep" merci !

12 votes

Pourquoi utilisez-vous un intervalle, un simple délai d'attente serait mieux sans avoir besoin de l'effacer, par exemple : jsfiddle.net/fgs5nwgn

4 votes

Je m'en tenais au contexte de la question. setTimeout fonctionnera, bien sûr.

120voto

Peter Bailey Points 62125

Utilisez setTimeout() à la place. La fonction de rappel sera alors chargée de déclencher le prochain délai d'attente, à partir duquel vous pourrez augmenter ou manipuler le timing.

EDIT

Voici une fonction générique que vous pouvez utiliser pour appliquer un délai de "décélération" pour N'IMPORTE QUEL appel de fonction.

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 votes

Par callback, voulez-vous dire que la dernière ligne de la fonction s'appelle elle-même récursivement avec un setTimeout(..., newInterval) ?

1 votes

Je suppose que c'est ce qu'il voulait dire. Je viens d'essayer et cela semble fonctionner. Merci, les gars !

0 votes

@joeydi, d'accord. Je voulais juste le préciser au cas où d'autres ne le feraient pas ;)

24voto

gnarf Points 49213

J'aime cette question - elle m'a inspiré un petit objet de timbre :

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

Exemple d'utilisation

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 votes

Merci - cela m'a mis sur la bonne voie pour un projet similaire sur lequel je travaille.

0 votes

Simple et efficace. Merci !

18voto

user28958 Points 66

J'avais la même question que le posteur original, j'ai trouvé cette solution. Je ne suis pas sûr de l'efficacité de cette solution ....

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

    }

0 votes

J'aime mieux cette réponse parce qu'elle en fait répond à la question de l'OP (et à la mienne). setTimeout est susceptible d'être retardé (par une utilisation à 100% du processeur, d'autres scripts, etc.) alors que setInterval N'EST PAS affecté par ces retards, ce qui le rend bien supérieur pour les activités en temps réel.

8 votes

Je suis sûr à 99% que votre affirmation sur setInterval est erroné @RozzA - Il est toujours soumis aux mêmes délais que tout autre JavaScript, et presque tous les navigateurs fixent également setInterval à 4ms. Avez-vous un lien vers un article à ce sujet ou autre ?

2voto

Je n'ai pas pu synchroniser et modifier la vitesse de mon setIntervals aussi et j'étais sur le point de poster une question. Mais je pense avoir trouvé un moyen. Elle doit certainement être améliorée car je suis un débutant. Donc, je serais heureux de lire vos commentaires/remarques à ce sujet.

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

Si vous voulez que les compteurs commencent à augmenter une fois la page chargée, mettez counter1() et counter2() sur foo() avant countingSpeed est appelé. Sinon, il prend speed millisecondes avant l'exécution. EDIT : Réponse plus courte.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X