Skip to content

Alléger l'Event Loop

L'Event Loop (ou "boucle d'événements") est au cœur de Node.js et est responsable de la gestion des tâches asynchrones. C'est grâce à lui que Node.js peut gérer de nombreuses connexions simultanément malgré le fait qu'il soit monocœur. Il fonctionne en vérifiant en permanence si des tâches sont prêtes à être exécutées et, le cas échéant, il les exécute.

Eviter les boucles longues

Quand on parle de "boucles longues", on fait référence à des itérations ou des calculs qui prennent beaucoup de temps à s'exécuter. Si une telle boucle est exécutée dans le thread principal de Node.js, elle peut "bloquer" l'Event Loop, ce qui signifie que pendant que cette boucle s'exécute, rien d'autre ne peut être traité (comme les requêtes entrantes, les réponses, les IO, etc.).

Exemple:

Imaginons que vous ayez le code suivant :

javascript
let sum = 0;
for (let i = 0; i < 1e9; i++) {
    sum += i;
}
console.log(sum);
let sum = 0;
for (let i = 0; i < 1e9; i++) {
    sum += i;
}
console.log(sum);

Ce code calcule la somme des premiers milliards de nombres. Cette boucle prendra un certain temps à s'exécuter. Pendant ce temps, si c'est dans un serveur Node.js, le serveur ne répondra pas aux requêtes entrantes car l'Event Loop est bloqué.

Diviser et traiter par petits morceaux

Si vous avez une opération longue, une approche consiste à diviser cette opération en plusieurs petites tâches. Chaque petite tâche est exécutée en un temps relativement court, permettant à l'Event Loop de traiter d'autres tâches entre les itérations.

Pour notre exemple précédent, au lieu de traiter tous les nombres en une seule boucle, nous pourrions diviser cela en plusieurs boucles, en utilisant des mécanismes asynchrones (comme setImmediate ou setTimeout) pour diviser le travail.

Exemple optimisé :

javascript
let sum = 0;
let i = 0;

function partialSum() {
    let end = i + 1e6;  // traiter par blocs de 1 million à la fois
    for (; i < end && i < 1e9; i++) {
        sum += i;
    }

    if (i < 1e9) {
        setImmediate(partialSum);  // Planifier la prochaine iteration
    } else {
        console.log(sum);  // Afficher le résultat final
    }
}

partialSum();
let sum = 0;
let i = 0;

function partialSum() {
    let end = i + 1e6;  // traiter par blocs de 1 million à la fois
    for (; i < end && i < 1e9; i++) {
        sum += i;
    }

    if (i < 1e9) {
        setImmediate(partialSum);  // Planifier la prochaine iteration
    } else {
        console.log(sum);  // Afficher le résultat final
    }
}

partialSum();

Ici, partialSum calcule la somme des nombres par blocs de 1 million à la fois. Après chaque bloc, nous utilisons setImmediate pour permettre à l'Event Loop de vérifier et d'exécuter d'autres tâches avant de revenir à la prochaine iteration de partialSum.

En adoptant cette approche, nous évitons de bloquer l'Event Loop pendant de longues périodes, permettant à notre application de rester réactive même pendant de lourds calculs.