Thursday, December 26, 2019

The Developer who blocked the Event Loop

Recently, our team started working on using Node.js v12 in our v10 app. Luckily, we have unit tests that cover most of the core features. In Node.js 12, one unit test failed. 😱

The test assert that the event loop isn't blocked, even when a large amount of data is processed. Data is processed using async patterns with promises. The unit test add a separate task, triggered with setTimeout, and should be executed during the processing of the large amount of data. But now it is processed after. What? 

Something has changed.


Everything is fine.

Oh no, the code is blocking the event loop.


Here's example code I've written for this post that will behave differently in Node.js 10 and 12.
setTimeout(() => log('first timeout: done!'));

setTimeout(() => {
  processData()
    .then(processData)
    .then(processData)
    .then(processData);
});

// this one should run before all the "processData" calls are done.
setTimeout(() => log('second timeout: done!'));

[full example here]

Breaking changes? 💔
There's a lot of good things in the blog and change log about the Node.js 12 release, but I can't find any breaking API changes. What about Node.js 11? I couldn't find anything about changed event loop behavior there either. 

Promises can block the Event Loop 💤
I found a blog post (linked below) and a GitHub conversation about harmonizing how tasks are prioritized in the browser and in Node.js. Promises and features like setTimeout are since Node.js 11 grouped into micro and macro tasks, with different prioritization in the event loop.

A simple hack 
Here's one way to make the example code behave like it does in Node.js 10. This will make the example code non blocking.

processData()
  .then(() => {
     setTimeout(processData);
});

I hope this post will give you some ideas and help when upgrading the Node.js version. 

Merry Christmas & Happy Coding!
🎅


References
New Changes to the Timers and Microtasks in Node v11.0.0
MacroTask and MicroTask execution order