Concurrency and Multithreading in TypeScript: Advanced Level
\n\nIn modern web development and server-side programming, application performance and responsiveness are critically important. TypeScript, being a superset of JavaScript, inherited its single-threaded execution model (Event Loop). However, for solving resource-intensive tasks (image processing, cryptography, complex calculations), asynchrony alone is not enough. At an advanced level, a developer needs to understand how to organize true multithreading and safe work with shared memory. In this article, we will analyze key mechanisms: Web Workers (browser), Worker Threads (Node.js), SharedArrayBuffer, and Atomics.
\n\n1. Web Workers: Parallelism in the Browser
\n\nWeb Workers are the primary way to run code in a separate thread in a browser environment. A Worker does not have access to the DOM, but can perform heavy computations without blocking the main (UI) thread.
\n\nCreating a Worker in TypeScript requires compiling a separate file. Let's look at an example: calculating large Fibonacci numbers.
\n\nFile worker.ts (compiles to 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\nFile 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(`Result: ${event.data}`); // Output after completion\n worker.terminate();\n};\n\nworker.onerror = (error) => {\n console.error('Worker error:', error.message);\n};\n\nImportant nuances:
\n- \n
- The Worker runs in a separate thread but does not have access to the global variables of the main thread. \n
- Data transfer occurs via copying (structured cloning). For large data, use Transferable objects (e.g., ArrayBuffer). \n
- For TypeScript, it is mandatory to specify types in messages to avoid runtime errors. \n
2. Worker Threads: Multithreading in Node.js
\n\nFor the server-side Node.js environment, the equivalent of Web Workers is the worker_threads module. It allows creating isolated threads with their own memory (V8 isolate). This is ideal for CPU-intensive operations such as hashing or JSON parsing.
Example: Creating a Worker for password hashing (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\nMain file (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 exited with code ${code}`));\n });\n });\n}\n\n(async () => {\n const hash = await hashPassword('mySecret', 'randomSalt');\n console.log(`Hash: ${hash}`);\n})();\n\nKey differences from Web Workers:
\n- \n
- Runs in Node.js, has access to the file system and process. \n
- Data transfer via