Optimise Node.js performance by avoiding broken promises - NearForm

TL;DR

Whenever JavaScript is executing in Node.js, the event loop is blocked.

Avoid writing promises that resolve in the same execution block/phase

Do not use Promises to wrap synchronous code

Do not create Promises in loops

Be extremely careful with nextTick()

Code tests and their results

The event loop itself is really nothing more than a simple do/while loop. Within each iteration of the loop, a number of queues are checked to see if there is any work to do. Each of these queues represents one of the “phases”

The Node.js event loop is implemented in C by the libuv dependency library. At each phase the callbacks that are triggered are C/C++ functions (what we’ll call the “native layer”). When that native layer function is invoked, it may or may not cause JavaScript to be executed. What’s important to know, however, is that while that native layer function is executing the event loop is stopped (for however long it takes to execute).

This means that while the callback is executing, the event loop cannot do the other things it is meant to do, like trigger timers, poll for operating system events, accept new HTTP requests, and so forth.

If the native layer function does execute JavaScript, it will call into V8 to invoke a JavaScript function. That JavaScript function may end up doing things like creating and resolving promises or calling process.nextTick() to schedule tasks. What is unique about promises and “nextTicks” is that those are stored in two separate queues that are processed independently of the event loop. Those queues are special in that they are drained every time control returns back to a native layer function that has used V8 to invoke JavaScript. This can happen many times per event loop turn and can happen many times during any phase of the event loop.

The basic rule of thumb is this: Whenever JavaScript is executing in Node.js, the event loop is blocked.

The longer your JavaScript takes to run, the longer your event loop will be blocked from doing anything else. The longer your event loop is blocked, the worse your Node.js application performance will be. It’s really that simple.