We are your Digital Ally™
Tech Talks: Concurrent Tasks in Node.js
education

Tech Talks: Concurrent Tasks in Node.js

Understanding how Node.js handles concurrent tasks — non-blocking I/O, blocking computation, and solutions using webworker-threads and Node Cluster.

Martin BielikDecember 23, 2015

Nodeschool workshops have begun in Bratislava, hosted by Progressbar. The first meet-up involved setting up the Node environment and working through workshoppers from the nodeschool site. Participants ranged from beginners to experts in JavaScript. A presentation focused on different approaches to handling concurrent tasks in Node.js, which forms the basis of this tech talk.

Single-Threaded Nature

JavaScript is from its nature single-threaded. That means when you run your web server (without load balancing or clusters) it uses only 1 CPU. Despite this limitation, Node.js is considered highly performant because applications are designed for non-blocking I/O operations.

Non-blocking I/O operations do not block further code execution until the operation finishes. In JavaScript these operations are asynchronous functions handled by callbacks, events or promises.

Examples of non-blocking I/O operations:

  • File reading
  • Database operations
  • HTTP requests
  • Bash execution

Operations that block execution include:

  • Factorial computation
  • Calculating Fibonacci series
  • Processing large data

Almost all operations which regular web servers are expected to do are I/O.

Practical Examples

Consider three API routes:

  1. /index — prints "Hello world!" (takes 3ms)
  2. /factorial — computes factorial of a large number — blocking (takes 3000ms)
  3. /fractal — requests database to compute a fractal — non-blocking (takes 3000ms)

Blocking Scenario (Factorial)

request('/factorial')
request('/index')
request('/index')

Response received:

193392295593259559 // waits 3 seconds
Hello world!
Hello world!

I had to wait 3 seconds to get "Hello World" responses. What happened is that the factorial operation blocked all execution and other requests had to wait until it finished.

Non-Blocking Scenario (Fractal)

request('/fractal')
request('/index')
request('/index')

Response received:

Hello world!
Hello world!
// waits 3 seconds
***** pretty fractal from db *****

The fractal operation did not block other requests. It created a query to the database, waited (but did not block) until it finished, and then sent a response back to the client.

Solutions for Time-Consuming Tasks

Webworker Threads

In today's web browsers it is known the concept of service workers. A worker runs in a different thread from the main JavaScript so that it does not block page rendering and other actions which affect user experience.

A library called webworker-threads implements the worker threads API for Node.js. When a new worker is created, the library creates a completely new process and runs it with given source code.

Features:

  • Send and receive data between server and worker
  • Create pools of workers
  • Main drawback: workers run in a completely different context from the server

Node Cluster

New versions of Node.js provide a Cluster API. It is possible to fork the current process and run multiple instances of the server.

The main process is called "Master" and forked processes are called "Workers". The basic use case is request load balancing between workers to utilize multiple CPUs. However, Node Cluster does not support thread pooling, so you have to implement it yourself.

Summary

Node.js is one of the most performant web servers in these days. Its single-threaded nature does not stop it from serving thousands of clients at a time with great responsiveness. The key is understanding that Node.js is dedicated for non-blocking I/O operations. For time-consuming tasks, developers can use the webworker-threads library or the built-in Node Cluster API.

© 2026