Contactez-nous

Introduction aux timers (setTimeout, setInterval)

Decouvrez comment utiliser les fonctions de minuterie (timers) setTimeout et setInterval en Node.js pour differer ou repeter l'execution de code de maniere asynchrone.

Planifier l'exécution dans le temps

Outre les opérations d'entrées/sorties (I/O) qui sont naturellement asynchrones, Node.js fournit des mécanismes pour planifier l'exécution de code à un moment ultérieur ou de manière répétée. Ce sont les timers (minuteries). Bien que souvent associées aux API des navigateurs web, ces fonctions sont également implémentées nativement dans Node.js (via libuv) et s'intègrent parfaitement au modèle asynchrone et à la boucle d'événements.

Les timers sont des outils fondamentaux pour introduire des délais, programmer des tâches périodiques, ou implémenter des mécanismes de timeout pour d'autres opérations asynchrones. Les deux fonctions de timer les plus couramment utilisées sont `setTimeout` et `setInterval`.

`setTimeout(callback, delay, ...args)` : Exécution différée unique

La fonction `setTimeout` permet de programmer l'exécution d'une fonction (le `callback`) une seule fois après un certain délai spécifié.

Syntaxe :

const timerId = setTimeout(callbackFunction, delayInMilliseconds, arg1, arg2, ...);
  • `callbackFunction` : La fonction à exécuter une fois le délai écoulé.
  • `delayInMilliseconds` : Le nombre de millisecondes à attendre avant d'exécuter le callback.
  • `arg1, arg2, ...` (Optionnel) : Des arguments supplémentaires qui seront passés à la `callbackFunction` lors de son exécution.

Comportement Asynchrone : Il est crucial de comprendre que `setTimeout` est asynchrone. Lorsque vous appelez `setTimeout`, Node.js enregistre simplement le callback et le délai auprès de la boucle d'événements, puis l'exécution de votre code continue immédiatement à la ligne suivante. Le callback ne sera exécuté que plus tard, lorsque la boucle d'événements atteindra la phase des timers et constatera que le délai est écoulé.

Garantie du délai : Le `delayInMilliseconds` représente un délai minimum, pas un délai exact garanti. Le callback ne s'exécutera jamais avant le délai spécifié, mais il pourrait s'exécuter après si la boucle d'événements est occupée par d'autres tâches (code synchrone long, autres callbacks) lorsque le délai expire. La boucle doit terminer sa tâche en cours et être libre pour pouvoir exécuter le callback du timer.

Exemple :

console.log("Début du script.");

const salutation = (nom) => {
  console.log(`Bonjour, ${nom} ! (Après délai)`);
};

// Programme l'exécution de salutation après 2 secondes, en passant "Alice" comme argument
const timerIdTimeout = setTimeout(salutation, 2000, "Alice");

console.log(`Timer programmé avec l'ID: ${timerIdTimeout}`);
console.log("Le script principal continue...");

// Pour annuler le timer avant qu'il ne s'exécute :
// clearTimeout(timerIdTimeout);

// Output possible:
// Début du script.
// Timer programmé avec l'ID: Timeout { ... } // (L'ID est un objet en Node.js)
// Le script principal continue...
// (environ 2 secondes plus tard)
// Bonjour, Alice ! (Après délai)

Valeur de retour : `setTimeout` renvoie un identifiant unique (un objet complexe en Node.js, différent de l'ID numérique des navigateurs) qui peut être utilisé pour annuler le timer avant son exécution à l'aide de la fonction `clearTimeout()`.

`setInterval(callback, delay, ...args)` : Exécution répétée

La fonction `setInterval` est similaire à `setTimeout`, mais au lieu d'exécuter le callback une seule fois, elle le programme pour une exécution répétée à intervalles réguliers.

Syntaxe :

const intervalId = setInterval(callbackFunction, delayInMilliseconds, arg1, arg2, ...);

Les paramètres sont les mêmes que pour `setTimeout` : le callback à exécuter, le délai (qui devient ici l'intervalle entre les exécutions), et les arguments optionnels pour le callback.

Comportement Répétitif : Après le délai initial, le callback est exécuté une première fois. Ensuite, Node.js tentera de l'exécuter à nouveau après chaque `delayInMilliseconds` écoulé.

Précision de l'intervalle : Comme pour `setTimeout`, le `delayInMilliseconds` est un intervalle cible, mais pas une garantie absolue. Si l'exécution du callback prend elle-même du temps, ou si la boucle d'événements est occupée par d'autres tâches, l'intervalle réel entre les exécutions peut être plus long que prévu. Si le callback prend plus de temps à s'exécuter que l'intervalle défini, les exécutions suivantes pourraient être retardées ou même s'accumuler (bien que Node.js tente d'éviter cela en ne mettant pas en file d'attente une nouvelle exécution si la précédente n'est pas terminée).

Exemple :

let compteur = 0;

const afficherCompteur = () => {
  compteur++;
  console.log(`Compteur : ${compteur}`);
  if (compteur >= 5) {
    console.log("Arrêt de l'intervalle.");
    clearInterval(intervalIdInterval); // Important d'arrêter l'intervalle !
  }
};

console.log("Démarrage de l'intervalle...");
// Exécute afficherCompteur toutes les 1 seconde (1000 ms)
const intervalIdInterval = setInterval(afficherCompteur, 1000);

console.log(`Intervalle programmé avec l'ID: ${intervalIdInterval}`);

// Output possible:
// Démarrage de l'intervalle...
// Intervalle programmé avec l'ID: Timeout { ... } 
// (après ~1s) Compteur : 1
// (après ~1s) Compteur : 2
// (après ~1s) Compteur : 3
// (après ~1s) Compteur : 4
// (après ~1s) Compteur : 5
// Arrêt de l'intervalle.

Valeur de retour et annulation : `setInterval` renvoie également un identifiant unique. Il est essentiel de stocker cet ID et d'utiliser la fonction `clearInterval(intervalId)` pour arrêter l'exécution répétée lorsque vous n'en avez plus besoin. Oublier de le faire peut entraîner une consommation inutile de ressources et des comportements inattendus (fuites de mémoire ou logique applicative erronée).

Annuler les timers : `clearTimeout` et `clearInterval`

Comme mentionné, Node.js fournit des fonctions pour annuler des timers avant leur exécution (pour `setTimeout`) ou pour arrêter leur répétition (pour `setInterval`).

  • `clearTimeout(timerId)` : Annule un timer unique qui a été programmé avec `setTimeout` en utilisant l'ID retourné par cet appel. Si le callback a déjà été exécuté, l'appel à `clearTimeout` n'a aucun effet.
  • `clearInterval(intervalId)` : Arrête les exécutions répétées d'un callback programmé avec `setInterval` en utilisant l'ID retourné. C'est crucial pour éviter que l'intervalle ne s'exécute indéfiniment.

Il est indispensable de conserver l'ID retourné par `setTimeout` ou `setInterval` si vous prévoyez d'avoir besoin d'annuler le timer plus tard.

Intégration à la boucle d'événements

Les callbacks des timers sont gérés par la phase "Timers" de la boucle d'événements. Lorsque vous appelez `setTimeout` ou `setInterval`, Node.js enregistre le callback et son délai d'expiration. A chaque tour, pendant la phase "Timers", la boucle vérifie quels timers ont expiré depuis le dernier tour. Si des timers ont expiré, leurs callbacks sont ajoutés à une file d'attente spécifique et sont exécutés séquentiellement (si la pile d'appels est vide).

Utiliser un délai de `0` (par exemple, `setTimeout(fn, 0)`) ne signifie pas que le callback s'exécutera immédiatement. Cela signifie qu'il s'exécutera dès que possible lors de la prochaine phase "Timers" de la boucle d'événements, après que les opérations I/O en cours dans la phase "Poll" et les callbacks `setImmediate` (phase "Check") du tour actuel aient été traités. C'est une technique parfois utilisée pour différer une exécution juste après la fin du code synchrone courant, mais `setImmediate` est souvent sémantiquement préférable pour ce cas d'usage précis.

En résumé, les timers `setTimeout` et `setInterval` sont des outils asynchrones essentiels pour contrôler le timing de l'exécution du code dans Node.js, en s'appuyant sur la boucle d'événements pour leur gestion. Leur nature non bloquante et leur dépendance à la disponibilité de la boucle d'événements sont des aspects clés à garder à l'esprit lors de leur utilisation.