Concurrency and Multithreading in TypeScript: A Complete Guide

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: From Theory to Practice



Modern web applications require high performance. TypeScript, running on top of Node.js, provides powerful tools for handling multiple tasks simultaneously. In this article, we'll explore how concurrency and multithreading work in TypeScript and learn to apply them in practice.



Concurrency vs Parallelism: Key Differences



Before diving into code, it's important to understand the difference between concurrency and parallelism.

  • Concurrency is the ability of a program to handle multiple tasks by switching between them. In JavaScript/TypeScript, this is implemented through the Event Loop and asynchronous operations.
  • Parallelism is the simultaneous execution of multiple tasks on different CPU cores. In Node.js, this is achieved through Worker Threads.


TypeScript (like JavaScript) is single-threaded by nature, but thanks to asynchrony and Worker Threads, we can effectively use both approaches.



Asynchrony: The Foundation of Concurrency in TypeScript



Asynchronous programming is the first step towards concurrency. Let's look at the main mechanisms.



Promises and async/await



Modern TypeScript actively uses async/await for working with asynchronous operations. This allows you to write code that looks synchronous but executes concurrently.



// Example of an async functionasync function fetchData(url: string): Promise<any> {  const response = await fetch(url);  return response.json();}

// Concurrent execution of multiple requestsasync function fetchAllData(): Promise<void> { const [users, posts, comments] = await Promise.all([ fetchData('/api/users'), fetchData('/api/posts'), fetchData('/api/comments') ]); console.log('All data loaded concurrently');}


Promise.all allows you to run multiple asynchronous operations simultaneously, which significantly speeds up execution compared to sequential execution.



Error Handling in Asynchronous Code



It's important to handle errors correctly during concurrent execution:



async function safeFetchAll(): Promise<void> {  try {    const results = await Promise.allSettled([      fetchData('/api/users'),      fetchData('/api/invalid'),      fetchData('/api/posts')    ]);        results.forEach((result, index) => {      if (result.status === 'fulfilled') {        console.log(`Request ${index} succeeded:`, result.value);      } else {        console.error(`Request ${index} failed:`, result.reason);      }    });  } catch (error) {    console.error('Critical error:', error);  }}


Worker Threads: True Multithreading in TypeScript



For CPU-intensive tasks (image processing, complex calculations), asynchrony alone is not enough. This is where Worker Threads come to the rescue — real execution threads.



Creating a Worker Thread



Let's look at an example of calculating Fibonacci numbers in a separate thread:



// fibonacci.worker.tsimport { parentPort } from 'worker_threads';

function fibonacci(n: number): number { if (n <= 1) return n; return fibonacci(n - 1) + fibonacci(n - 2);}

parentPort?.on('message', (n: number) => { const result = fibonacci(n); parentPort?.postMessage(result);});


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

function runFibonacci(n: number): Promise<number> { return new Promise((resolve, reject) => { const worker = new Worker(path.resolve(__dirname, 'fibonacci.worker.ts')); worker.postMessage(n); worker.on('message', (result: number) => { resolve(result); worker.terminate(); }); worker.on('er

Blogs

Book Recommendations