🛫 The basics of threading and concurrency

Shortly and briefly: while using traditional languages 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 respond at all while this operation gets 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 basis 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.

So:

❓How to deal with concurrency issues with JavaScript ?

📌 The JavaScript concurrency model and asynchronicity behaviors for code parallelism

As you might see 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 a time and each task will be queued to be processed.

But as we saw above, sometimes you will need to do multiple things at a 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 called « The event loop ».

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

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

For a web browser, you have fetch or setTimeout as an example.

or as an example. For NodeJS you have readFile or writeFile as an example, that delegate to the system IO.

Once calling such actions, the system takes 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, which 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:

Callback functions , that will receive parameters from the OS once called

, that will receive parameters from the OS once called Or JavaScript Promise that resolve or reject (using async-await as an example)

✋🏻⚠️ I won’t develop 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:

Fetch data from a remote API… And then write something in a file.

✋🏻⚠️ All the following codes are providing stubs functions which are only delaying the function return statement using JS Promise. This produces 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 hasn’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:

Sequenced program execution

Nonexistent code parallelism

The guarantee that for each topic the API call has returned and the file has been trying to be written with a success/failure, before going to the next iteration.

Synchronous behavior using async

While this can be nice sometimes for some use cases to guarantee sequencing when content has 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 other in terms of dependency and side effects, our callback loopOccurence is almost a pure function, as it doesn’t have a side effects 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 happens 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 tells the interpreter to not wait for the function to respond before going to the next iteration of the loop.

This approach leverages 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 mean 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 other 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 combination of the functional programming 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 promises and will « fast fail » if any of the promises 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 an 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 application's performance and responsiveness by using parallelism.