Skip to main content

Command Palette

Search for a command to run...

Improving Performance in Node.js: Blocking the Event Loop

Updated
3 min read
M

As a former 3D Animator with more than 12 years of experience, I have always been fascinated by the intersection of technology and creativity. That's why I recently shifted my career towards MERN stack development and software engineering, where I have been serving since 2021.

With my background in 3D animation, I bring a unique perspective to software development, combining creativity and technical expertise to build innovative and visually engaging applications. I have a passion for learning and staying up-to-date with the latest technologies and best practices, and I enjoy collaborating with cross-functional teams to solve complex problems and create seamless user experiences.

In my current role as a MERN stack developer, I have been responsible for developing and implementing web applications using MongoDB, Express, React, and Node.js. I have also gained experience in Agile development methodologies, version control with Git, and cloud-based deployment using platforms like Heroku and AWS.

I am committed to delivering high-quality work that meets the needs of both clients and end-users, and I am always seeking new challenges and opportunities to grow both personally and professionally.

Welcome back! Before we delve into strategies for improving performance, it’s important to understand the potential pitfalls that can arise when the event loop is blocked in a Node.js server. To illustrate this, let’s build a simple example.

Setting Up the Example

We’ll create a basic Express server to demonstrate the effects of blocking the event loop. Here’s how we’ll proceed:

  1. Create a project folder and initialize a Node.js package:

     mkdir performance-example
     cd performance-example
     npm init -y
    
  2. Install Express:

     npm install express
    
  3. Create a server.js file and set up an Express application:

     const express = require('express');
     const app = express();
    
     // Root route
     app.get('/', (req, res) => {
         res.send('Performance Example');
     });
    
     // Timer route
     app.get('/timer', (req, res) => {
         delay(9000); // Delay response for 9 seconds
         res.send('Ding Ding Ding!');
     });
    
     // Delay function
     function delay(duration) {
         const startTime = Date.now();
         while (Date.now() - startTime < duration) {
             // Busy waiting
         }
     }
    
     app.listen(3000, () => {
         console.log('Server is running on port 3000');
     });
    
  4. Start the server:

     node server.js
    

Testing the Server

Observing Blocking Behavior

Here’s where the problem begins:

  1. Open two browser tabs. In the first tab, request the /timer endpoint. In the second tab, quickly request the / endpoint while the first request is still processing.

  2. Notice that the response to the second request is delayed until the timer route completes.

  3. This happens because the event loop is blocked by the delay function, preventing other requests from being processed.

Why Blocking Happens

  • The delay function uses a while loop to simulate a delay, which continuously checks the elapsed time. This blocks the event loop, preventing it from handling other operations.

  • Node.js processes JavaScript code on a single thread, and while the delay function is executing, no other code can run.

Real-World Implications

Although this example uses a contrived while loop, similar issues can occur with real-world scenarios such as:

  • Computationally intensive tasks in JavaScript.

  • Synchronous file or database operations.

  • Improper use of third-party libraries.

Measuring Performance Impact

  • The first request to /timer takes approximately 9 seconds, as expected.

  • Subsequent requests to any endpoint (e.g., /timer) are delayed until the /timer endpoint finishes execution.

Next Steps

To address these performance bottlenecks, we’ll explore techniques to prevent blocking the event loop, such as:

  • Offloading intensive tasks to worker threads.

  • Using asynchronous programming patterns.

  • Leveraging built-in non-blocking APIs.

Stay tuned as we investigate these strategies and ensure our server remains responsive under heavy load.