Concurrency and Multithreading in TypeScript: Advanced Level

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Concurrency and Multithreading in TypeScript: Advanced Level



In modern web development and server-side applications using TypeScript, the ability to effectively work with concurrency and multithreading is becoming critically important. Although JavaScript is a single-threaded language, the runtime environment (browser or Node.js) provides powerful tools for parallel task execution. In this article, we will explore advanced techniques for working with concurrency in TypeScript, including Worker Threads, SharedArrayBuffer, Atomics, and synchronization patterns.



1. Fundamental Basics: Event Loop and async/await



Before diving into multithreading, it is important to understand how the Event Loop works in TypeScript. Concurrency in a single-threaded environment is achieved through non-blocking I/O and asynchronous operations.



Consider an example using Promise.allSettled() for concurrent execution of multiple asynchronous tasks with error handling:



interface TaskResult<T> {  status: 'fulfilled' | 'rejected';  value?: T;  reason?: Error;}

async function runConcurrentTasks<T>( tasks: Promise<T>[]): Promise<TaskResult<T>[]> { const results = await Promise.allSettled(tasks); return results.map(result => { if (result.status === 'fulfilled') { return { status: 'fulfilled', value: result.value }; } else { return { status: 'rejected', reason: result.reason }; } });}

// Usageconst task1 = fetchData('/api/users');const task2 = fetchData('/api/posts');const task3 = fetchData('/api/comments');

const results = await runConcurrentTasks([task1, task2, task3]);


2. Worker Threads in Node.js: True Multithreading



For CPU-intensive tasks (e.g., image processing, cryptography, complex calculations), real threads are necessary. In Node.js, Worker Threads are used for this purpose.



Let's create a typed Worker with TypeScript:



// worker.tsimport { parentPort, workerData } from 'worker_threads';

interface WorkerInput { data: number[]; operation: 'sum' | 'multiply';}

interface WorkerOutput { result: number; duration: number;}

if (parentPort) { const input: WorkerInput = workerData; const start = performance.now(); let result: number; if (input.operation === 'sum') { result = input.data.reduce((acc, val) => acc + val, 0); } else { result = input.data.reduce((acc, val) => acc * val, 1); } const output: WorkerOutput = { result, duration: performance.now() - start }; parentPort.postMessage(output);}


Now let's create a manager for controlling multiple Workers:



// threadPool.tsimport { Worker } from 'worker_threads';import path from 'path';

class ThreadPool<TInput, TOutput> { private workers: Worker[] = []; private taskQueue: Array<{ input: TInput; resolve: (value: TOutput) => void; reject: (reason?: any) => void; }> = [];

constructor( private workerScript: string, private poolSize: number = 4 ) { this.initialize(); }

private initialize(): void { for (let i = 0; i < this.poolSize; i++) { const worker = new Worker(this.workerScript); worker.on('message', (result: TOutput) => { const task = this.taskQueue.shift(); if (task) { task.resolve(result); } worker.postMessage(this.taskQueue[0]?.input); });

worker.on('error', (error) => { const task = this.taskQueue.shift(); if (task) { task.reject(error); } });

this.workers.push(worker); } }

async execute(input: TInput): Promise<TOutput> { return new Promise((resolve, reject) => { this.ta

Blogs

Book Recommendations