Introduction : pourquoi votre site "rame" et qui est responsable
\n\nImaginez un restaurant où un seul serveur prend les commandes, sert les plats, lave la vaisselle et fait la caisse en même temps. Le chaos, n'est-ce pas ? C'est à peu près ainsi que fonctionne le JavaScript monothread, si l'on ne gère pas correctement les tâches. Lorsque nous écrivons du code qui fait tout à la fois — charger des données, traiter des clics, animer — le navigateur se fige et l'utilisateur voit une interface "pensive".
\n\nAujourd'hui, nous allons comprendre comment les files d'attente de tâches en JavaScript aident à transformer ce chaos en un système structuré. Vous découvrirez comment l'Event Loop distribue les priorités, en quoi les micro-tâches diffèrent des macro-tâches, et comment les tâches de fond JavaScript permettent de ne pas bloquer le thread principal. À la fin, des exemples pratiques vous attendent, que vous pouvez immédiatement intégrer dans votre projet.
\n\nComment fonctionne l'Event Loop : le chef d'orchestre des tâches
\n\nAu cœur de toute asynchronie se trouve l'Event Loop JavaScript. C'est un mécanisme qui tourne en boucle et demande : "Y a-t-il quelque chose à exécuter ? Et des micro-tâches ? Et du rendu ?". Si vous vous êtes déjà demandé pourquoi setTimeout ne s'exécute pas immédiatement, alors que Promise.then le fait presque instantanément — la réponse se trouve ici.
La pile d'appels (Call Stack)
\nC'est l'endroit où les fonctions arrivent pour une exécution immédiate. Tant que la pile est occupée, rien d'autre ne se produit. Si votre fonction calcule un million de nombres — le navigateur se figera, car la pile ne se libérera pas.
\n\nLa file d'attente des macro-tâches (Macrotask Queue)
\nC'est ici qu'arrivent setTimeout, setInterval, les événements DOM (clics, défilement), le chargement des ressources. L'Event Loop prend une tâche de cette file, l'exécute, puis vérifie les micro-tâches, ensuite effectue le rendu de la page — et reprend la macro-tâche suivante.
La file d'attente des micro-tâches (Microtask Queue)
\nEt voici le royaume des Promise, queueMicrotask, MutationObserver. Les micro-tâches ont la priorité la plus élevée. Dès que la pile est vide, l'Event Loop exécute TOUTES les micro-tâches avant de passer à la macro-tâche suivante. C'est pourquoi Promise.resolve().then() se déclenche plus rapidement que setTimeout.
console.log('1');\n\nsetTimeout(() => {\n console.log('2');\n}, 0);\n\nPromise.resolve().then(() => {\n console.log('3');\n});\n\nconsole.log('4');\n\n// Affichage : 1, 4, 3, 2\n\n\nCet exemple est un classique. setTimeout (macro-tâche) est différé, même avec un délai nul, tandis que Promise.then (micro-tâche) s'exécute immédiatement après le code synchrone. Comprendre cet ordre est la clé pour écrire un code asynchrone prévisible.
Tâches de fond : comment ne pas bloquer l'interface
\n\nEt maintenant, le problème principal : que faire si vous devez effectuer un travail lourd (traitement d'images, calculs complexes, analyse de données) ? Si vous l'exécutez dans le thread principal — l'interface se bloquera. La solution — les tâches de fond JavaScript.
\n\nWeb Workers — le vrai multithreading
\nLes Web Workers JS permettent d'exécuter du code dans un thread séparé. Il n'a pas accès au DOM, mais peut échanger des messages avec le thread principal. C'est l'outil idéal pour le traitement des files d'attente JS en arrière-plan.
\n\n// main.js\nconst worker = new Worker('worker.js');\n\nworker.postMessage({ data: [1, 2, 3, 4, 5, 6] });\n\nworker.onmessage = (event) => {\n console.log('Résultat du worker :', event.data);\n};\n\n// worker.js\nself.onmessage = (event) => {\n const numbers = event.data.data;\n // Travail lourd : filtrage des nombres pairs\n const result = numbers.filter(n => n % 2 === 0);\n self.postMessage(result);\n};\n\n\nRemarquez : le thread principal n'est pas bloqué. L'utilisateur peut cliquer, défiler, saisir du texte — tout fonctionnera de manière fluide pendant que le worker calcule.
\n\n