JS Optimizations: Non-blocking Code

In the world of JS, everything we do is ideally supposed to be non-blocking. It’s important in JS because your app only runs on one thread, and if that thread gets blocked… the entire app gets blocked.

In my work project, we have some number crunching logic in which a single function may run for several minutes. These functions don’t do any form of I/O, just data manipulation using loops. The problem is, standard loops are blocking. Whether it’s a for loop, map, filter or reduce, it’s going to block.

In order to unblock the code, we’d need to 1.) use recursion and 2.) use the setImmediate function to give the event queue time to breathe and resolve other function calls.

Here’s an example of some blocking code:

The timer callback will never run because longFunc() blocks the app, then immediately clears the timer.

A quick fix would be to make the longFunc an async function and add setImmediate inside the while loop like so:

That would unblock the loop by postponing the next iteration until the next tick, allowing the app to do other stuff. But that only works for a while loop, not for forEach, map, filter, etc.

A more versatile solution is this:

The non-blocking function has a recursive inner-function called loop that evokes itself while a condition is true. Your blocking logic would go inside the conditional statement before setImmediate. For us, we process a single row of a table inside the loop. Any small atomic operation would be suitable. The performance penalty seems practically moot.

Another added benefit of using setImmediate is that is prevents exceeding the call stack size. Now if we could figure out to parallelize the logic across multiple threads without copying the data, that would be amazing.

Leave a Reply

Be the First to Comment!

wpDiscuz