Understand JavaScript sequencing and asynchronous behaviors to leverage code parallelism.

A little guide on asynchronicity and how you can improve your applications performances and responsiveness leveraging JS concurrency model.

Andréas Hanss
Nov 4, 2019 · 7 min read

JavaScript is using a single threaded concurrency model, this article will present some thoughts and examples to understand the basics of the concurrency in JS.

We will study this through two demonstrations: first with a sequenced and synchronous loop execution and then with a parallel and asynchronous loop.

🗓 Summary

🛫 The basics of threading and concurrency

Shortly and briefly: while using traditional language such as C or Java, sometimes you are doing things, that take some time for the CPU to compute.

During this time, you cannot execute other code than the current instructions. Your program can get frozen and the UI might not responds at all while this operation get completed.

This is completely « normal » and you will have to deal with it.

➡️ How to avoid UI freezing ?

To fix this you can use something called a thread, which allows you to delegate some code execution in sub-process. This leads to non-blocking actions and parallel code execution thanks to multi-threading.

This is the basic of code parallelism and concurrency in standard/former languages.

Concurrency is a complicated chapter of programming, especially for beginners. I won’t go deeper than this in it here. The above sample is enough to understand what is following, as JavaScript is not a multi-threaded language.


❓How to deal with concurrency issues with JavaScript ?

📌 The JavaScript concurrency model and asynchronicity behaviors for code parallelism

As you might seen above JavaScript is using a single threaded language and this is true for any JS engine implementation such as V8 from Chrome, JavaScriptCore for Apple’s Safari or Hermes from Facebook for React native.

❓What does that mean ?

It means that JavaScript will be able to execute only one task at time and each tasks will be queued to be processed.

But as we saw above, sometimes you will need to do multiple things at time or you’ll have some instructions that can take many seconds to process, which leads to freezes because of thread blocking.

⚙️ But Javascript has no multi-threads

So the only way to deal with that is to delegate somehow code execution to an external handler, continue script execution and then execute a callback code once the execution has been processed.

And that is what is implemented by the engine in something call « The event loop ».

JavaScript can delegate asynchronous behaviors to the the OS using some « native » functions provided by the kernel.

Most of time those are IO instructions but it can be something else.

Once calling such actions, the system take the orders, execute all the instructions on his own command in sub-processes…

⚙️ The JavaScript Event loop

Then the system will call your program back once this is done: this is part of the famous JS Event Loop.

If you have no idea what is that about, you could check here : https://medium.com/front-end-weekly/javascript-event-loop-explained-4cd26af121d4.

💣 Quickly & Briefly: The Event loop is an engine sequence that is looping indefinitely while the program is running, that will execute statements in a queue given a specific order.

Those statements are provided by code functions and callback instructions.

Callback instructions provide some code that needs to be executed once the system finished the asynchronous code execution, such as reading a file on the system.

We speak of callback instructions but in fact it can be:

✋🏻⚠️ I won’t developed what a promise is here, you could have a look at this very well written guide: https://developers.google.com/web/fundamentals/primers/promises

🚀 Example : Async loop vs Sync loop in JavaScript

In the following example we will iterate through an array of topics to demonstrate the difference between blocking loop and non-blocking loop using asynchronous behaviors.

This array contains topics, for each we need to:

✋🏻⚠️ All the following code are providing stubs functions which are only delaying the function return statement using JS Promise. This produce the same behavior as deferring a code execution to the system.

You could also have a look at what are async / await statements here

In order to use the following snippet, you will need to create a index.js file copy the snippets into and run a npm init -y && npm install chalk in order to get this small utility library which gives text color in the console.

The simply run the script with node ./index.js

❶ First approach : « Synchronous » code execution

We start with the « synchronous » approach, this one will be blocking execution within the loop using an async function with the await keyword as long as the called function haven’t returned.

💡Hint: In fact this is not a really synchronous as you expect. Using await will just ensure the code is executed sequentially within the function. Whenever you await, you let other stuff happen, and at some later point continue where you awaited.

This leads to the following assumptions:

Synchronous behavior using async

While this can be nice sometimes for some use cases to guarantee sequencing when content have side-effects on each other, in the following use case, this is not the best way to achieve this goal.

By running the following script in a NodeJS program You can see that the total script execution time is pretty high compared to the deferring duration, but as we chain, the take time is growing linearly.

❷ Second approach: Asynchronous code execution & parallelism

As each of our themes values are unrelated between each others in terms of dependency and side effect, our callback loopOccurence is almost a pure function, as it doesn’t have side effect on our application. (to be a real pure function it shouldn’t have any side effects at all)

👨🏻‍🔬 A pure function is a function that taking the same arguments, will produce and return the same result each time. This function is also not causing any side effects outside of it’s scope.

And because of that, I invite you to just see what happen if you remove the await keyword in the previous snippet as described below.

Enabling and leveraging parallelism thanks to our pure function loopOccurence

💡 async / await keywords are tools to control the execution flow of a function. Removing the await keyword tell the interpreter to not wait for the function to responds before going to the next iteration of the loop.

This approach leverage parallelism as the JS engine sends the three requests at the same time.

💡Hint: Oh yeah, I forgot, you’re not using await inside of the loop but it doesn’t means you don’t have to await at all, in fact you’ll need to handle errors and ensure that everything complete well. We’ll see that in the next section.

Those are great tools, use them as much as you can.

➡️ Welcome to asynchronicity and parallelism.

The performances and the responsiveness of the application are greatly improved and we can still keep our sequencing inside of each theme loop by first waiting to get the API call return state and then create the file.

Looking at the execution time, this is way better than our first approach.

Why ? Because JS delegate parallel execution, so the script can access quicker to others instructions (loop iterations in our case), which results in better performances.

🎁 Bonus : Using functional programming forEach instruction

We could have also replaced our for…of loop with a function from functional programming named forEach. The result would be exactly the same as you can see here.

💡 Wants to know more about forEach function? Click here!

Using functional programming we are achieving the same goal of parallelism

⚡️🔓The most secure, errors safe and efficient way : map + Promise.all

In fact I was missing something really important above: ensuring that everything worked fine and handling errors.

You can improve the above snippet with the following using a combinaison of the functional programing map function along with Promise.all function.

The first one will helps to map promise that will be passed to the second one. The second one will receive an array of promise an will « fast fail » if any of the promise in the given array fail. This is your error handling scenario.

const everythingOk = await Promise.all(themes.map(loopOccurence));

🚛 Takeaway / TLDR; 📦

JavaScript applications run on a single thread. You will need to use asynchronous mechanism to deal with this single thread attribute.

Asynchronous mechanisms leverage JavaScript callbacks and Promises.

async / await keywords are tools to control the execution flow within a function.

Using asynchronicity can greatly improve your applications performances and responsiveness by using parallelism.

Within loops instructions: you can use forEach or for…of statement to get asynchronous iterations. On the other side: you can use for…of with await keyword or generators to get synchronous code execution within the function.

🙏🏻 Acknowledgments

People at Reddit for helping me improve this article which was a bit clumsy at first.

JavaScript in Plain English

Learn the web's most important programming language.

Andréas Hanss

Written by

👨🏻‍💻Javascript Tech leads @ Kaliop 🇫🇷 — react | react-native | modern js |🔥 Firebase — https://modern-javascript.fr. Passionnated about learning.

JavaScript in Plain English

Learn the web's most important programming language.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade