setTimeout ou setInterval?

763

Autant que je sache, ces deux morceaux de 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);

Y a-t-il une différence entre l'utilisation de setTimeout et setInterval ?

Damovisa
la source
6
Si vous souhaitez de bons détails sur le fonctionnement des minuteries dans JS, John Resig a écrit un bon article sur ce sujet
Rafael
9
il y a aussi la différence évidente que setTimeout nécessite cette ligne de code supplémentaire pour continuer à se propager, ce qui a l'inconvénient d'être un problème de maintenance mais l'avantage de vous permettre de changer la période facilement
annakata
essayez ceci jsfiddle.net/pramendra/Y4vEV
Pramendra Gupta
4
Merci @JapanPro mais je n'ai jamais vraiment eu de problème pour que les délais d'attente fonctionnent. Ce message parlait de la différence et des éléments à utiliser.
Damovisa

Réponses:

670

Ils essaient essentiellement de faire la même chose, mais l' setIntervalapproche sera plus précise que l' setTimeoutapproche, car setTimeoutattend 1000 ms, exécute la fonction et définit ensuite un autre délai d'expiration. Ainsi, la période d'attente est en fait un peu plus de 1000 ms (ou beaucoup plus si votre fonction prend beaucoup de temps à exécuter).

Bien que l'on puisse penser que setIntervalcela s'exécutera exactement tous les 1000 ms, il est important de noter que setIntervalcela retardera également, car JavaScript n'est pas un langage multithread, ce qui signifie que - s'il y a d'autres parties du script en cours d'exécution - l'intervalle aura attendre que cela se termine.

Dans ce violon , vous pouvez clairement voir que le délai d'attente prendra du retard, tandis 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 en haut à quelque chose de petit comme 20 (ce qui signifie qu'elle essaiera de s'exécuter 50 fois par seconde), l'intervalle n'atteindra jamais tout à fait une moyenne de 50 itérations par seconde.

Le retard est presque toujours négligeable, mais si vous programmez quelque chose de vraiment précis, vous devriez opter pour une minuterie auto-ajustable (qui est essentiellement une minuterie basée sur le délai d'attente qui s'ajuste constamment en fonction du retard créé)

David Snabel-Caunt
la source
4
Andy avait une suggestion similaire. En théorie, cela signifie-t-il que si l'exécution de la méthode prend plus de 1000 ms, vous pouvez en exécuter plusieurs simultanément?
Damovisa
14
Théoriquement, oui. En pratique, non, car Javascript ne prend pas en charge le multithreading. Si votre code prend plus de 1000 ms, il gèlera le navigateur.
Kamiel Wanrooij
61
Techniquement, le code ne s'exécutera pas exactement tous les 1000 ms, car il dépend de la résolution du temporisateur et de la présence ou non d'un autre code. Votre argument est toujours valable.
Matthew Crumley
10
setInterval est différent de deux manières: 1. setInterval n'est pas récursif et setInterval appellera pour la première fois votre fonction après l'heure indiquée tandis que setTimeout sera appelé pour la première fois sans délai et après cela, il appellera à nouveau après l'heure indiquée. Après la première exécution, ils fonctionnent presque de la même manière.
Hafiz
5
La différence est que setTimeout ne se répète pas. Il vous permet d'exécuter un script après un temps défini, mais une seule fois. D'autre part, setInterval répétera ce script jusqu'à ce qu'il soit arrêté avec clearTimeout ().
Leander
648

Y a-t-il une différence?

Oui. Un Timeout 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 ., un déclenchement du délai / intervalle avec *et l'exécution de code JavaScript avec [-----], les chronologies ressemblent à:

Timeout:

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

Interval:

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

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

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

• représente un tir d'intervalle qui n'a pas pu exécuter son code tout de suite, et a été mis en attente à la place.

Les intervalles essaient donc de «rattraper» pour revenir à la date prévue. Mais ils ne font pas la queue l'un sur l'autre: il ne peut y avoir qu'une seule exécution en attente par intervalle. (S'ils faisaient tous la queue, le navigateur se retrouverait avec une liste toujours plus longue d'exécutions en suspens!)

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

x représente un tir d'intervalle qui n'a pas pu être exécuté ou être mis en attente, donc a été rejeté.

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

Lequel utilisez-vous et pourquoi?

Chained-Timeout donne un créneau garanti de temps libre au navigateur; Interval essaie de s'assurer que la fonction qu'il exécute s'exécute aussi près que possible de ses heures planifiées, au détriment de la disponibilité de l'interface utilisateur du navigateur.

Je considérerais un intervalle pour les animations ponctuelles que je voulais être aussi fluide que possible, tandis que les délais d'attente chaî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 une mise à jour triviale qui se déclenche toutes les 30 secondes ou quelque chose), vous pouvez utiliser l'une ou l'autre en toute sécurité.

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

bobince
la source
Mais la raison du choix entre Interval et Timeout est-elle valable même pour les plates-formes sans navigateur, comme par exemple WebOS ou JIL?
Vid L
2
Une belle façon de faire des délais d'attente chaînés sur des fonctions anonymes: setTimeout (function () {setTimeout (arguments.callee, 10)}, 10)
Justin Meyer
1
En termes de compatibilité des navigateurs, bien que tous les navigateurs proposent les deux méthodes, leurs performances sont différentes.
unigg
"Mais alors il y a des chances que cela ne prenne en charge rien d'autre que vous utilisez" donc très vrai
Basic
1
boîte à rythmes par projet chrome utilisant setTimeout ("Schedule ()", 0); Ainsi, le navigateur n'aura pas de pile inutile lorsqu'il s'agit d'un onglet d'arrière-plan pour Chrome ou d'un manque de ressources.
Elliot Yap
91

setInterval ()

setInterval()est une méthode d'exécution de code basée sur un intervalle de temps qui a la capacité native d'exécuter de manière répétée un script spécifié lorsque l'intervalle est atteint. Il ne doit pas être imbriqué dans sa fonction de rappel par l'auteur du script pour le faire boucler, car il boucle par défaut . Il continuera à tirer à intervalles, sauf si vous appelez clearInterval().

Si vous voulez boucler du code pour des animations ou sur un tick 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 de code basée sur le temps qui n'exécutera un script qu'une seule fois lorsque l'intervalle sera atteint. Il ne se répétera pas à moins que vous ne l'utilisiez pour boucler le script en imbriquant l' setTimeout()objet à l'intérieur de la fonction qu'il appelle à exécuter. S'il est adapté à la boucle, il continuera de 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 produise une fois après une période spécifiée, utilisez setTimeout(). En effet, il ne s'exécute qu'une seule fois lorsque l'intervalle spécifié est atteint.

Haris
la source
6
Belle explication mais notez que l'OP comprend la différence de base dans les exemples fournis par l'OP. En particulier, notez que dans l' setTimeout()exemple du PO , setTimeout()est appelé récursivement , alors qu'il setInterval()ne l'est pas.
DavidRR
44

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

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

myTimeoutFunction();

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

contre

function myTimeoutFunction()
{
    doStuff();
}

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

// later on...
clearInterval(timerId);
Kamiel Wanrooij
la source
35
Je ne vois pas comment vous ne gardez pas la trace de l'ID du temporisateur dans le cas de setInterval. Il vient juste de sortir de la fonction.
Kekoa
1
Une autre option avec setTimeoutest plutôt que d'enregistrer l'id ajouter une ifinstruction pour définir uniquement le délai d'expiration suivant lorsqu'une condition est vraie.
nnnnnn
7
Kekoa, bon point. Mais vous ne devez enregistrer l'ID d'intervalle qu'une seule fois. L'ID de délai d'attente change probablement à chaque appel, vous devez donc garder une trace de ces changements. Le code qui veut effacer le délai d'attente doit en quelque sorte avoir accès à la valeur actuelle de cette variable. De plus, il est impossible d'effacer le délai d'expiration pendant l'exécution doStuffcar l'ID n'est pas valide. Cependant, il n'est pas vraiment nécessaire d'enregistrer les identifiants de délai d'expiration. Au lieu de cela, vous pouvez simplement arrêter d'appeler setTimeout.
Robert
4
D'après mon expérience, la plupart du temps, vous voulez pouvoir annuler même en utilisant setTimeout. 99% du temps que vous souhaitez annuler avant le prochain appel, pas après la fin du suivant.
Kamiel Wanrooij
23

Je trouve la setTimeoutméthode plus facile à utiliser si vous souhaitez annuler le délai:

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

myTimeoutFunction();

De plus, si quelque chose tournait mal dans la fonction, elle cesserait simplement de se répéter à la première erreur, au lieu de répéter l'erreur toutes les secondes.

Guffa
la source
20

La différence 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

kmario23
la source
7
Belle explication concise mais notez que l'OP comprend la différence de base dans les exemples fournis par l'OP. En particulier, notez que dans l' setTimeout()exemple du PO , setTimeout()est appelé récursivement , alors qu'il setInterval()ne l'est pas.
DavidRR
14

Lorsque vous exécutez une fonction à l'intérieur de setInterval, qui fonctionne plus longtemps que timeout-> le navigateur sera bloqué.

- Par exemple, doStuff () prend 1500 sec. à exécuter et vous le faites: setInterval (doStuff, 1000);
1) Le navigateur exécute doStuff () qui prend 1,5 seconde. être éxecuté;
2) Après environ 1 seconde, il essaie de réexécuter doStuff () . Mais la précédente doStuff () est toujours exécutée-> donc le navigateur ajoute cette exécution à la file d'attente (à exécuter après la première exécution).
3,4, ..) Même ajout à la file d'attente d'exécution pour les prochaines itérations, mais doStuff () de la précédente est toujours en cours ...
En conséquence, le navigateur est bloqué.

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

Serg Hospodarets
la source
1
Je ne sais pas pourquoi personne n'a trouvé de valeur dans cette réponse!
Randika Vishman
9

J'utilise setTimeout.

Apparemment, la différence est que setTimeout appelle la méthode une fois, setInterval l'appelle de manière répétée.

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

Bravax
la source
2
Oui, j'ai cette différence, mais les deux morceaux de code que j'ai fournis devraient alors faire la même chose ...
Damovisa
Ummm oui ... j'aurais pensé ... mais selon dcaunt et son décompte des voix ce n'est pas tout à fait ce qui se passe.
Bravax
9

Votre code aura des intervalles d'exécution différents, et dans certains projets, tels que les jeux en ligne, il n'est pas acceptable. Tout d'abord, que devez-vous faire, pour que votre code fonctionne avec les mêmes intervalles, 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 monothread. 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 avez un délai aléatoire de 1 à 3 secondes, ce ne sera absolument pas acceptable (après une minute, le délai sera d'environ 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 il aura un délai d'expiration de 995 ms et le résultat sera stable.

deg
la source
7

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

setIntervalva généralement planifier la prochaine itération juste après le début de l'itération précédente, à moins que la fonction est toujours en cours . Si c'est le cas, setIntervalattendra jusqu'à la fin de la fonction. Dès qu'elle se produit, la fonction est immédiatement relancée - il n'y a pas d'attente pour la prochaine itération selon le calendrier (comme ce serait dans des conditions sans fonction de dépassement de temps). Il n'y a également aucune 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 console:

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

La waitfonction n'est qu'un assistant de blocage de threads - appel ajax synchrone qui prend exactement 2500 millisecondes de traitement côté serveur:

function wait() {
    $.ajax({
        url: "...",
        async: false
    });
}
jwaliszko
la source
1
"pas de situation avec des itérations parallèles en cours" - oui, cela devrait être impossible. Le JavaScript côté client a un modèle d'exécution unique, donc rien (gestionnaires d'événements, etc.) ne se produit jamais en même temps. C'est pourquoi rien ne se passe (et le navigateur ne répond pas) pendant l'appel ajax synchrone.
MrWhite
Le navigateur est-il réactif dans les quelques ms entre "intervalles"? Un autre événement se déclencherait-il s'il est en attente? (Merci pour les tests entre +1)
MrWhite
1
Selon MDN, il est considéré comme une " utilisation dangereuse " si la fonction peut s'exécuter plus longtemps que l'intervalle. Un setTimoutappel récursif est préférable.
MrWhite
6

Pour le voir un peu différemment: setInterval assure qu'un code est exécuté à chaque intervalle donné (c'est-à-dire 1000 ms, ou combien vous spécifiez) tandis que setTimeout définit le temps qu'il «attend» pour exécuter le code. Et comme il faut des millisecondes supplémentaires pour exécuter le code, il s'ajoute à 1000 ms et ainsi, setTimeout s'exécute à nouveau à des moments inexacts (plus de 1000 ms).

Par exemple, les temporisations / comptes à rebours ne sont pas effectués avec setTimeout, ils le sont avec setInterval, pour garantir qu'il ne tarde pas et que le code s'exécute à l'intervalle donné exact.

CatalinBerta
la source
5

SetInterval et setTimeout renvoient un identifiant de temporisation que vous pouvez utiliser pour annuler l'exécution, c'est-à-dire avant le déclenchement des délais. Pour annuler, appelez clearInterval ou clearTimeout comme ceci:

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.

Helgi
la source
4

Vous pouvez valider la réponse de Bobince par vous-même lorsque vous exécutez le javascript suivant ou vérifiez ce 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);
});
Gudradain
la source
3

Eh bien, setTimeout est meilleur 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 à cet onglet, le diaporama (sur lequel le code a été utilisé) changeait très rapidement, au lieu de toutes les 5 secondes qu'il devrait avoir. En fait, cela se reproduit à mesure que je le teste davantage et que ce soit la faute du navigateur ou non n'est pas important, car avec setTimeout, cette situation est complètement impossible.

Nino
la source
On dirait que vous avez appelé setInterval dans la fonction que vous appeliez. C'est ainsi que vous bouclez avec setTimeout, mais avec setInterval, vous créez en fait une boucle entièrement nouvelle à chaque appel.
Stephen R
2

La différence est évidente dans la console:

entrez la description de l'image ici

testCoder
la source
2

Il suffit d'ajouter à ce qui a déjà été dit, mais la version setTimeout du code atteindra également le Maximum call stack sizequi l'empêchera de fonctionner. Puisqu'il n'y a pas de cas de base pour la fonction récursive, vous ne pouvez donc pas l'exécuter indéfiniment.

Maaz
la source
Je ne pense pas que ce soit vrai. Voir ici stackoverflow.com/questions/8058612/…
Kevin Wheeler
-1

La différence la plus générique entre et setInterval (expression, durée) est que

setTimeout () exécutera l'expression seulement UNE FOIS et cela après cette durée spécifiée.

cependant,

setInterval () exécutera l'expression dans INFINITE-LOOP après chaque durée spécifiée.

Anshu Aditya
la source
-5

Je pense SetIntervalet je suis SetTimeoutdifférent. SetIntervalexécute le bloc en fonction de l'heure définie tandis que, SetTimeoutexécute le bloc de code une fois.

Essayez ces ensembles de codes après les secondes du compte à rebours:

setInterval(function(e){
    alert('Ugbana Kelvin');
}, 2000);

puis essayez

setTimeout(function(e){
    alert('Ugbana Kelvin');
}, 2000);

Vous pouvez voir les différences par vous-même.

Ugbana Chukwujindu Kelvin
la source
Cela ne répond pas à la question. settimeout () peut être utilisé récursivement pour donner le même résultat que setinterval. La question portait sur les performances de ces deux options.
Tomas Gonzalez