Concurrence en TypeScript : threads, goroutines et async/await — on pratique

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Concurrence en TypeScript : de l'Event Loop aux Web Workers

\n\n

Avez-vous déjà remarqué comment votre navigateur ou votre application Node.js « se fige » lors de l'exécution d'une opération mathématique complexe ou du traitement d'un gros JSON ? Ce sentiment d'impuissance familier lorsque l'interface cesse de répondre aux clics et le serveur aux nouvelles requêtes. Tout cela parce que par défaut, JavaScript (et son frère strict TypeScript) est un langage monothread. Mais cela ne signifie pas que nous sommes condamnés à des programmes lents. Au contraire, une utilisation judicieuse de la concurrence en TypeScript permet de créer des applications rapides et réactives.

\n\n

Dans cet article, nous ne nous contenterons pas d'énumérer des termes. Nous verrons comment fonctionnent réellement async/await, ce qui se cache sous le capot de l'Event Loop, s'il est possible d'utiliser des « goroutines » en TypeScript comme en Go, et quand il faut utiliser de véritables threads via les Web Workers. C'est parti !

\n\n

1. Asynchrone vs Parallélisme : quelle est la différence ?

\n\n

Avant de plonger dans le code, mettons-nous d'accord sur les termes. Beaucoup confondent ces concepts, à tort.

\n\n
    \n
  • Asynchrone (concurrence) — c'est la capacité d'un programme à démarrer une tâche, passer à une autre pendant que la première attend (par exemple, une réponse du serveur), puis y revenir plus tard. À un instant donné, une seule instruction est exécutée.
  • \n
  • Parallélisme — c'est l'exécution de deux tâches ou plus littéralement au même moment sur différents cœurs du processeur.
  • \n
\n\n

TypeScript nous offre l'asynchrone par défaut. Le parallélisme, quant à lui, nécessite la création de threads séparés — dans le navigateur, ce sont les Web Workers, dans Node.js — les worker_threads. Retenez cette différence, sinon vous risquez d'écrire un code qui « ralentira » à cause du blocage du thread principal.

\n\n

2. Event Loop et callbacks — le fondement de la concurrence en TypeScript

\n\n

Le secret principal de l'asynchrone en JavaScript/TypeScript est l'Event Loop (boucle d'événements). Imaginez que vous avez une file d'attente de tâches. Le thread principal prend une tâche, l'exécute, si elle est synchrone — il renvoie immédiatement le résultat. Si c'est une opération asynchrone (par exemple, setTimeout ou fetch), elle est envoyée « de côté » (dans Web API ou libuv), tandis que le thread principal continue d'exécuter le code suivant.

\n\n

Lorsque l'opération asynchrone se termine, son callback est placé dans une file d'attente (Task Queue ou Microtask Queue). L'Event Loop vérifie constamment si la pile d'appels est vide, et si c'est le cas, elle prend la première tâche de la file d'attente et l'exécute.

\n\n
// Exemple simple qui le démontre\nconsole.log('1. Début');\n\nsetTimeout(() => {\n    console.log('3. Timer déclenché');\n}, 0);\n\nPromise.resolve().then(() => {\n    console.log('2. Microtask exécutée');\n});\n\nconsole.log('4. Fin');\n\n// Sortie : 1, 4, 2, 3
\n\n

Remarquez : Promise (microtask) s'est exécuté avant setTimeout (macrotask), même si le délai du timer est de 0 ms. C'est une connaissance importante pour l'optimisation TypeScript.

\n\n

3. Async/Await — le sucre qui change tout

\n\n

Avec l'arrivée d'ES2017, le monde JS s'est divisé en « avant » et « après ». Async/await est un sucre syntaxique autour des promesses, qui rend le code asynchrone similaire au code synchrone. Il n'ajoute pas de threads, mais améliore radicalement la lisibilité.

\n\n
// Fonction simulant un délai\nfunction delay(ms: number): Promise<void> {\n    return new Promise(resolve => setTimeout(resolve, ms));\n}\n\n// Fonction asynchrone utilisant async/await\nasync function fetchUserData(userId: number): Promise<string> {\n    console.log(`Demande des données de l'utilisateur ${userId}...`);\n    await delay(2000); // Simulation d'une requête réseau\n    return `Données de l'utilisateur ${userId}`;\n}\n\nasync function main() {\n    console.log('Début');\n    const user1 = await fetchUserData(1);\n    console.log(                

Blogs

Book Recommendations