Differences Between setTimeout and setInterval in JavaScript

Les fonctions setTimeout et setTimeout sont des outils fondamentaux en JavaScript pour la planification de tâches. Il est essentiel de comprendre leur fonctionnement interne, car JavaScript s'exécute dans un moteur de manière mono-thread.

Ces fonctions ne créent pas de threads parallèles. Elles insèrent simplement le code à exécuter dans une file d'attente (event queue) miantenue par le moteur JavaScript, à un moment spécifié. L'insertion dans la file n'implique pas une exécution immédiate.

Fonctionnement de setTimeout

Considérons l'exemple suivant, déclenché par un événement click :

function gestionClic() {
    // Bloc A
    setTimeout(() => {
        // Traitement différé
    }, 200);
    // Bloc B
}

Lors du clic, le Bloc A s'exécute en premier. L'appel à setTimeout informe le moteur de planifier le rappel (le « Traitement différé ») pour insertion dans la file d'attente après 200ms. L'exécution du code dans gestionClic se poursuit immédiatement avec le Bloc B.

Le moment exact d'exécution du rappel dépend de la durée du Bloc B.

  • Si le Bloc B prend plus de 200ms, le rappel est déjà inséré dans la file pendant son exécution. Cependant, il ne s'exécutera qu'après la fin complète de gestionClic, car le thread est occupé.
  • Si le Bloc B prend moins de 200ms, le rappel est inséré alors que le thread est inactif, et s'exécute donc quasi-instantanément après les 200ms.

Comportement de setInterval

Contrairement à setTimeout, setInterval tente de planifier des exécutions répétées à intervalles réguliers. Ce mécanisme présente deux particularités notables :

  1. Les intervalles peuvent être « sautés » si la file d'attante contient déjà une occurrence en attente.
  2. Le temps effectif entre deux appels peut varier et ne pas correspondre exactement à l'intervalle spécifié.
function demarrerTraitementPeriodique() {
    setInterval(() => {
        // Traitement long
    }, 200);
}

Supposons que le rappel de setInterval soit planifié à t=0ms, t=200ms, t=400ms, etc. Si le premier rappel (à t=0ms) s'exécute pendant 350ms (dépassant les 400ms), la prochaine insertion prévue à t=400ms sera ignorée. Le moteur JavaScript ne permet qu'une seule occurrence non exécutée d'un intervalle dans la file d'attente. L'exécution suivante se produira après la fin de la première (vers t=350ms), et le prochain intervalle sera recalculé à partir de là.

Alternative récursive avec setTimeout

Pour obtenir un comportement plus prévisible avec une pause constante entre chaque fin et le début de l'exécution suivante, une approche récursive avec setTimeout est souvent préférable :

function executerPeriodiquement(delai) {
    // Traitement
    setTimeout(() => executerPeriodiquement(delai), delai);
}

executerPeriodiquement(200);

Cette méthode garantit qu'un nouveau délai de 200ms est appliqué uniquement après l'achèvement du traitement courant, éliminant ainsi les risques d'accumulation ou de saut d'intervalles dans la file d'attente des événements.

Étiquettes: JavaScript setTimeout setInterval event loop asynchronous programming

Publié le 20 juin à 18h58