Concurrence et multithreading en TypeScript : niveau avancé
\n\nDans le développement web moderne et la programmation serveur, les performances et la réactivité des applications sont cruciales. TypeScript, en tant que surcouche de JavaScript, a hérité de son modèle d'exécution monothread (Event Loop). Cependant, pour résoudre des tâches gourmandes en ressources (traitement d'images, cryptographie, calculs complexes), l'asynchrone seul ne suffit pas. À un niveau avancé, le développeur doit comprendre comment organiser un véritable multithreading et un travail sécurisé avec la mémoire partagée. Dans cet article, nous allons détailler les mécanismes clés : Web Workers (navigateur), Worker Threads (Node.js), SharedArrayBuffer et Atomics.
\n\n1. Web Workers : parallélisme dans le navigateur
\n\nLes Web Workers sont le principal moyen d'exécuter du code dans un thread séparé dans un environnement navigateur. Un Worker n'a pas accès au DOM, mais peut effectuer des calculs lourds sans bloquer le thread principal (UI).
\n\nLa création d'un Worker en TypeScript nécessite la compilation d'un fichier séparé. Prenons un exemple : le calcul de grands nombres de Fibonacci.
\n\nFichier worker.ts (compilé en worker.js) :
\n// worker.ts\nself.onmessage = (event: MessageEvent<number>) => {\n const n = event.data;\n const fib = (num: number): number => {\n if (num <= 1) return num;\n return fib(num - 1) + fib(num - 2);\n };\n const result = fib(n);\n self.postMessage(result);\n};\n\nFichier main.ts :
\n// main.ts\nconst worker = new Worker(new URL('./worker.js', import.meta.url));\n\nworker.postMessage(40);\n\nworker.onmessage = (event: MessageEvent<number>) => {\n console.log(`Résultat : ${event.data}`); // Affichage après la fin\n worker.terminate();\n};\n\nworker.onerror = (error) => {\n console.error('Erreur Worker :', error.message);\n};\n\nPoints importants :
\n- \n
- Le Worker s'exécute dans un thread séparé, mais n'a pas accès aux variables globales du thread principal. \n
- Le transfert de données se fait par copie (clonage structurel). Pour les grandes données, utilisez des Transferable objects (par exemple, ArrayBuffer). \n
- Pour TypeScript, il est obligatoire de spécifier les types dans les messages afin d'éviter les erreurs d'exécution. \n
2. Worker Threads : multithreading dans Node.js
\n\nPour l'environnement serveur Node.js, l'équivalent des Web Workers est le module worker_threads. Il permet de créer des threads isolés avec leur propre mémoire (V8 isolate). C'est idéal pour les opérations intensives en CPU, comme le hachage ou l'analyse JSON.
Exemple : création d'un Worker pour le hachage de mot de passe (worker.ts) :
\n// crypto-worker.ts\nimport { parentPort, workerData } from 'worker_threads';\nimport { createHash } from 'crypto';\n\nif (parentPort) {\n const { password, salt } = workerData;\n const hash = createHash('sha256')\n .update(password + salt)\n .digest('hex');\n parentPort.postMessage(hash);\n}\n\nFichier principal (main.ts) :
\n// main.ts\nimport { Worker } from 'worker_threads';\nimport path from 'path';\n\nfunction hashPassword(password: string, salt: string): Promise<string> {\n return new Promise((resolve, reject) => {\n const worker = new Worker(path.resolve(__dirname, 'crypto-worker.js'), {\n workerData: { password, salt }\n });\n\n worker.on('message', resolve);\n worker.on('error', reject);\n worker.on('exit', (code) => {\n if (code !== 0) reject(new Error(`Worker terminé avec le code ${code}`));\n });\n });\n}\n\n(async () => {\n const hash = await hashPassword('mySecret', 'randomSalt');\n console.log(`Hachage : ${hash}`);\n})();\n\nDifférences clés avec les Web Workers :
\n- \n
- Fonctionne dans Node.js, accès au système de fichiers et au processus. \n
- Transfert de données via