web-dev-qa-db-fra.com

setTimeout ou setInterval?

Autant que je sache, ces deux éléments de code javascript se comportent de la même manière:

Option A:

function myTimeoutFunction()
{
    doStuff();
    setTimeout(myTimeoutFunction, 1000);
}

myTimeoutFunction();

Option B:

function myTimeoutFunction()
{
    doStuff();
}

myTimeoutFunction();
setInterval(myTimeoutFunction, 1000);

Existe-t-il une différence entre setTimeout et setInterval ?

723
Damovisa

Ils essaient essentiellement de faire la même chose, mais l'approche setInterval sera plus précise que l'approche setTimeout, étant donné que setTimeout attend 1000 ms, exécute la fonction puis définit un autre délai d'expiration. Donc, la période d'attente est en réalité un peu plus de 1000 ms (ou beaucoup plus si l'exécution de votre fonction prend beaucoup de temps).

Bien que l'on puisse penser que setInterval exécute exactement toutes les 1000 ms, il est important de noter que setInterval retardera également, car JavaScript n'est pas un processus multitâche language, ce qui signifie que - s’il existe d’autres parties du script en cours d’exécution - l’intervalle devra attendre que cela se termine.

Dans ce violon , vous pouvez clairement voir que le délai d’attente va prendre du retard, alors que l’intervalle est presque tout le temps à presque 1 appel/seconde (ce que le script essaie de faire). Si vous modifiez la variable de vitesse du haut en une valeur minuscule telle que 20 (ce qui signifie qu’elle essaiera de courir 50 fois par seconde), l’intervalle n’atteindra jamais une moyenne de 50 itérations par seconde.

Le délai est presque toujours négligeable, mais si vous programmez quelque chose de très précis, vous devriez opter pour un minuteur à ajustement automatique (qui est essentiellement un minuteur basé sur un délai qui ajuste en permanence lui-même pour le retard, il est créé)

631

Y a-t-il une différence?

Oui. Un délai d'attente s'exécute un certain temps après l'appel de setTimeout (); un intervalle s'exécute un certain temps après le déclenchement de l'intervalle précédent.

Vous remarquerez la différence si votre fonction doStuff () prend un certain temps à s'exécuter. Par exemple, si nous représentons un appel à setTimeout/setInterval avec ., le déclenchement du timeout/intervalle avec * et de l'exécution de code JavaScript avec [-----], les échéances ressemblent à ceci:

Timeout:

.    *  .    *  .    *  .    *  .
     [--]    [--]    [--]    [--]

Interval:

.    *    *    *    *    *    *
     [--] [--] [--] [--] [--] [--]

La complication suivante est si un intervalle se déclenche alors que JavaScript est déjà occupé à faire quelque chose (comme la gestion d'un intervalle précédent). Dans ce cas, l'intervalle est mémorisé et se produit dès que le gestionnaire précédent se termine et renvoie le contrôle au navigateur. Ainsi, par exemple, pour un processus doStuff () parfois court ([-]) et parfois long ([-----]):

.    *    *    •    *    •    *    *
     [-]  [-----][-][-----][-][-]  [-]

• représente un tir d'intervalle qui n'a pas pu exécuter son code immédiatement et a été mis en attente.

Donc, des intervalles tentent de "rattraper" pour revenir dans les temps. Mais ils ne font pas la queue les uns sur les autres: il ne peut y avoir qu'une seule exécution en attente par intervalle. (S'ils faisaient tous la queue, il resterait une liste sans cesse croissante d'exécutions exceptionnelles au navigateur.)

.    *    •    •    x    •    •    x
     [------][------][------][------]

x représente un intervalle de tir qui ne peut pas être exécuté ou est en attente, il a donc été ignoré.

Si votre fonction doStuff () prend habituellement plus de temps à exécuter que l'intervalle qui lui est défini, le navigateur consommera 100% de la CPU en essayant de la réparer et risque de devenir moins réactif.

Lequel utilisez-vous et pourquoi?

Chained-Timeout donne un créneau horaire garanti au navigateur. Interval tente de s’assurer que la fonction en cours d’exécution est exécutée aussi près que possible de ses heures planifiées, aux dépens de la disponibilité de l’interface utilisateur du navigateur.

Je considérerais un intervalle pour les animations uniques que je voulais être aussi fluide que possible, tandis que les délais d'attente enchaînés sont plus polis pour les animations en cours qui auraient lieu tout le temps pendant le chargement de la page. Pour des utilisations moins exigeantes (comme un programme de mise à jour trivial qui se déclenche toutes les 30 secondes ou quelque chose du genre), vous pouvez utiliser en toute sécurité.

En termes de compatibilité de navigateur, setTimeout est antérieur à setInterval, mais tous les navigateurs que vous allez rencontrer aujourd'hui prennent en charge les deux. Le dernier bloqueur depuis de nombreuses années était IE Mobile dans WinMo <6.5, mais nous espérons que cela aussi est derrière nous.

637
bobince

setInterval ()

setInterval() est une méthode d'exécution du code basée sur un intervalle de temps qui a la capacité native d'exécuter plusieurs fois un script spécifié lorsque cet intervalle est atteint. Il devrait ne pas être imbriqué dans sa fonction de rappel par l'auteur du script pour le mettre en boucle, car il boucle par défaut . Il continuera de tirer à cet intervalle, à moins que vous appeliez clearInterval().

Si vous souhaitez utiliser du code pour les animations ou sur une coche d'horloge, utilisez setInterval().

function doStuff() {
    alert("run your code here when time interval is reached");
}
var myTimer = setInterval(doStuff, 5000);

setTimeout ()

setTimeout() est une méthode d'exécution du code basée sur le temps qui n'exécute qu'un script une fois lorsque l'intervalle est atteint. Il ne se répétera pas à moins que vous ne l'utilisiez pour boucler le script en imbriquant l'objet setTimeout() à l'intérieur de la fonction qu'il appelle à exécuter. S'il est conçu pour la boucle, il continuera à tirer à l'intervalle, sauf si vous appelez clearTimeout().

function doStuff() {
    alert("run your code here when time interval is reached");
}
var myTimer = setTimeout(doStuff, 5000);

Si vous voulez que quelque chose se passe une fois après une période de temps spécifiée, utilisez alors setTimeout(). En effet, il ne s'exécute qu'une fois lorsque l'intervalle spécifié est atteint.

85
Haris

SetInterval facilite l'annulation de l'exécution future de votre code. Si vous utilisez setTimeout, vous devez garder une trace de l’identifiant de la minuterie au cas où vous souhaiteriez l’annuler ultérieurement.

var timerId = null;
function myTimeoutFunction()
{
    doStuff();
    timerId = setTimeout(myTimeoutFunction, 1000);
}

myTimeoutFunction();

// later on...
clearTimeout(timerId);

versus

function myTimeoutFunction()
{
    doStuff();
}

myTimeoutFunction();
var timerId = setInterval(myTimeoutFunction, 1000);

// later on...
clearInterval(timerId);
41
Kamiel Wanrooij

Je trouve la méthode setTimeout plus facile à utiliser si vous souhaitez annuler le délai d'attente:

function myTimeoutFunction() {
   doStuff();
   if (stillrunning) {
      setTimeout(myTimeoutFunction, 1000);
   }
}

myTimeoutFunction();

De plus, si quelque chose ne va pas dans la fonction, la répétition d'erreur à la première erreur cessera, au lieu d'être répétée toutes les secondes.

21
Guffa

La différence même réside dans leurs objectifs.

setInterval()
   -> executes a function, over and over again, at specified time intervals  

setTimeout()
   -> executes a function, once, after waiting a specified number of milliseconds

C'est aussi simple que ça

Des détails plus élaborés ici http://javascript.info/tutorial/settimeout-setinterval

16
kmario23

Lorsque vous exécutez une fonction dans setInterval, qui fonctionne plus longtemps que timeout-> le navigateur sera bloqué.

- Par exemple, doStuff () prend 1500 secondes. être exécuté et vous faites: setInterval (doStuff, 1000);
1) Exécution du navigateur doStuff () () , ce qui prend 1,5 seconde. être éxecuté;
2) Après environ 1 seconde, il tente de s'exécuter à nouveau doStuff () . Mais previous doStuff () est toujours exécuté-> donc le navigateur ajoute cette exécution à la file d'attente (à exécuter une fois que la première est terminée).
3,4, ..) Le même ajout à la file d’exécution pour les prochaines itérations, mais doStuff () de la précédente sont toujours en cours...
En conséquence, le navigateur est bloqué.

Pour éviter ce problème, le meilleur moyen consiste à exécuter setTimeout dans setTimeout pour émuler setInterval .
Pour corriger les délais d'attente entre les appels setTimeout, vous pouvez utiliser la technique alternative à correction automatique à setInterval de JavaScript .

12
Serg Hospodarets

J'utilise setTimeout.

Apparemment, la différence est que setTimeout appelle la méthode une fois, setInterval l'appelle plusieurs fois.

Voici un bon article expliquant la différence: Tutoriel: Minuteries JavaScript avec setTimeout et setInterval

7
Bravax

J'ai fait un test simple de setInterval(func, milisec), parce que j'étais curieux de savoir ce qui se produit lorsque la consommation de temps de la fonction est supérieure à la durée de l'intervalle.

setInterval will généralement planifiera la prochaine itération juste après le début de l'itération précédente, sauf si la fonction est toujours en cours d'exécution. Si tel est le cas, setInterval attendra jusqu'à la fin de la fonction. Dès que cela se produit, la fonction est immédiatement réactivée - il n'y a pas d'attente pour la prochaine itération conformément au planning (comme ce serait le cas dans des conditions sans fonction dépassée dans le temps). Il n'y a pas non plus de situation avec des itérations parallèles en cours d'exécution.

J'ai testé cela sur Chrome v23. J'espère que c'est une implémentation déterministe sur tous les navigateurs modernes.

window.setInterval(function(start) {
    console.log('fired: ' + (new Date().getTime() - start));
    wait();
  }, 1000, new Date().getTime());

Sortie de la console:

fired: 1000    + ~2500 ajax call -.
fired: 3522    <------------------'
fired: 6032
fired: 8540
fired: 11048

La fonction wait est simplement une aide au blocage de threads - appel ajax synchrone qui prend exactement 2500 millisecondes du traitement côté serveur:

function wait() {
    $.ajax({
        url: "...",
        async: false
    });
}
5
jwaliszko

Votre code aura des valeurs d’exécution différentes et, dans certains projets, tels que les jeux en ligne, ce n’est pas acceptable. Premièrement, que devez-vous faire pour que votre code fonctionne avec les mêmes valeurs, vous devez remplacer "myTimeoutFunction" par ceci:

function myTimeoutFunction()
{
    setTimeout(myTimeoutFunction, 1000);
    doStuff();
}
myTimeoutFunction()

Après ce changement, il sera égal à

function myTimeoutFunction()
{
    doStuff();
}
myTimeoutFunction();
setInterval(myTimeoutFunction, 1000);

Mais vous n'aurez toujours pas de résultat stable, car JS est mono-thread. Pour l'instant, si le thread JS est occupé par quelque chose, il ne pourra pas exécuter votre fonction de rappel et son exécution sera différée de 2 à 3 ms. Si vous avez 60 exécutions par seconde, et chaque fois que vous aurez un délai aléatoire de 1 à 3 secondes, ce ne sera absolument pas acceptable (après une minute, ce sera autour de 7200 ms), et je peux vous conseiller d’utiliser quelque chose comme ceci:

    function Timer(clb, timeout) {
        this.clb = clb;
        this.timeout = timeout;
        this.stopTimeout = null;
        this.precision = -1;
    }

    Timer.prototype.start = function() {
        var me = this;
        var now = new Date();
        if(me.precision === -1) {
            me.precision = now.getTime();
        }
        me.stopTimeout = setTimeout(function(){
            me.start()
        }, me.precision - now.getTime() + me.timeout);
        me.precision += me.timeout;
        me.clb();
    };

    Timer.prototype.stop = function() {
        clearTimeout(this.stopTimeout);
        this.precision = -1;
    };

    function myTimeoutFunction()
    {
        doStuff();
    }

    var timer = new Timer(myTimeoutFunction, 1000);
    timer.start();

Ce code garantira une période d'exécution stable. Même le thread sera occupé et votre code sera exécuté après 1005 ms, la prochaine fois qu'il aura un délai d'expiration de 995 ms et le résultat sera stable.

4
degr

Pour le regarder un peu différemment: setInterval assure qu'un code est exécuté à chaque intervalle donné (c'est-à-dire 1000 ms ou la quantité que vous spécifiez) pendant que setTimeout définit le délai pendant lequel il attend jusqu'à ce qu'il exécute le code. Et comme il faut plus de millisecondes pour exécuter le code, il ajoute 1000 ms et, par conséquent, setTimeout s'exécute à nouveau à des moments inexacts (plus de 1000 ms).

Par exemple, les minuteries/comptes à rebours ne sont pas effectués avec setTimeout, ils le sont avec setInterval, pour éviter tout retard et que le code s'exécute à l'intervalle donné.

4
CatalinBerta

SetInterval et setTimeout renvoient tous deux un identifiant de minuterie que vous pouvez utiliser pour annuler l'exécution, c'est-à-dire avant que les délais ne soient déclenchés. Pour annuler, appelez clearInterval ou clearTimeout de la manière suivante:

var timeoutId = setTimeout(someFunction, 1000);
clearTimeout(timeoutId);
var intervalId = setInterval(someFunction, 1000),
clearInterval(intervalId);

En outre, les délais d'attente sont automatiquement annulés lorsque vous quittez la page ou fermez la fenêtre du navigateur.

3
Helgi

Eh bien, setTimeout est préférable dans une situation, comme je viens de l’apprendre. J'utilise toujours setInterval, qu'il me reste à exécuter en arrière-plan pendant plus d'une demi-heure. Lorsque je suis revenu sur cet onglet, le diaporama (sur lequel le code était utilisé) changeait très rapidement, au lieu de toutes les 5 secondes. En fait, cela se produit à nouveau lorsque je le teste davantage et que ce soit la faute du navigateur ou pas du tout, ce n'est pas important, car avec setTimeout, cette situation est complètement impossible.

2
Nino

Vous pouvez valider bobince answer par vous-même lorsque vous exécutez le code javascript suivant ou cochez cette case JSFiddle

<div id="timeout"></div>
<div id="interval"></div>

var timeout = 0;
var interval = 0;

function doTimeout(){
    $('#timeout').html(timeout);
    timeout++;
    setTimeout(doTimeout, 1);
}

function doInterval(){
    $('#interval').html(interval);
    interval++;
}

$(function(){
    doTimeout();
    doInterval();
    setInterval(doInterval, 1);
});
2
Gudradain

Il suffit d’ajouter à ce qui a déjà été dit, mais la version du code setTimeout atteindra également le Maximum call stack size qui l’arrêtera de fonctionner. Puisqu'il n'y a pas de cas de base pour que la fonction récursive s'arrête, vous ne pouvez donc pas la lancer pour toujours.

1
Maaz

La différence est évidente dans la console:

enter image description here

1
testCoder