You might have heard the term asynchronous programming if you have been in the tech community for some time.
I used to pull my hair several times when I started learning JavaScript, trying to understand this concept.
However, you don’t have to pull your hair as i will try my best to make this concept easy to understand.
Who is this article for ?
This article is aimed at beginners, however if you are a developer with some years under your belt and hoping to refresh your knowledge on this concept, I hope this article has what you are looking for.
What you’ll learn;
What asynchronous and synchronous programming are.
Ways to implement asynchronous code in JavaScript.
JavaScript and the browser.
Pre-requisite;
To get the most out of this article, I recommend you have a basic knowledge of JavaScript, if not, there are tons of tutorials on YouTube. I’ll wait for you.
Now, let’s start!
What is synchronous programming ?
When we make mention of synchronous in JavaScript, what we mean is that, the instructions that you have written is executed sequentially one after the other, one by one.
code snippet;
JavaScript is a single threaded language, it means the instructions are executed one at a time. In the code snippet above, this is the logical pattern that JavaScript follows after the function is invoked;
The length variable is initialized to 4
The length variable is multiplied by 4 and the resulting value is assigned to the perimeter variable
The perimeter variable is logged to the console
As this instruction follows a sequential pattern, if the first line has not finished its execution, the second line isn’t executed hence we say it’s a blocking code / synchronous.
However, in modern web applications, you might want to request some information from a server, be it user’s information or comments etc.
In this scenario, using synchronous approach will cause your application to hang or freeze for the duration that the api request will take before the UI becomes responsive again.
This is not a good user experience, that is why asynchronous programming exists to solve this kind of problem.
You Need to Understand Asynchronous programming.
Any instruction that doesn’t interrupt with JavaScript main thread when it is executing can be termed as an asynchronous instruction.
Using the example about the UI introduced earlier, this will mean that whiles the UI is being mounted to the DOM, there is some code which is also fetching users information from a server, both occurring at the same time. Hence we say the execution of the instruction is independent and concurrent to the main JavaScript thread.
As modern web applications can become data intensive and very interactive is why you need to understand and know how to implement asynchronous code.
How to implement asynchronous code
There are three main ways in which we can write asynchronous code in JavaScript, they are;
Callbacks
Promises
Async / await
Let’s understand each of them;
Callbacks- call me please
Now, suppose you have two functions, A() and B(), for some reason you decided to pass B() to A() and you instructed A() to execute B() after some time, say 2 seconds, B() is then considered a callback function.
code snippet;
With callbacks, we can write code that can be executed later in time or when an event occurs.
As seen from the code snippet above, the code is querying a dom element, and logging the element after 2 seconds.
setTimeout() is a function that takes in another function (the callback) and execute it after 2 seconds.
In actual application, we can make a network request or even listen for event within the application.
code snippet;
There is a drawback when using callbacks, because functions are passed to other functions, as evident in the code snippet above, we get to a point where the functions are deeply nested that it makes it difficult to read and debug.
This is called callback hell.
Promises, which is another way to write asynchronous code aims to solve this drawback.
Promises - promise me
Mdn docs gives a very good definition of promise.
“The Promise object represent the eventual completion (or failure ) of an asynchronous operation and its resulting value.”
for you to understand it better, use this analogy;
Suppose a friend promise you to buy you a gift, at the time that your friend made the promise, the gift is not available yet( pending ), so there are two scenarios that can happen;
Your friend is not able to meet up with the promise, hence fails
Your friend is able to buy you the gift, hence it’s fulfilled
As we can see, initially we had no idea whether the promise will be fulfilled or not, but “eventually” we will have a feedback which will be either our friend will buy us the gift (fulfilled) or not (failed).
This is the exact same thing that happens when using promises in JavaScript.
Promises have the following states;
Pending - when the promise is defined
Resolve - when the promise has executed successfully
Reject - when the promise failed after execution
Let’s see how we can define a promise and handle the different states.
code snippet;
To create a promise, we use the promise constructor new Promise, which accepts a callback function, the callback function is called executor function, it accepts the arguments resolve and reject - which are functions provided to the executor function.
This is how we can handle the different states;
code snippet;
let’s take it step by step.
We initialize a success variable to true, as before we create a promise with the constructor and assign it to the promiseObject variable.
We check if the success variable is true, then we pass a string value to the resolve argument which will be passed to .then handler and if the success variable is not true, we pass a string value to the reject argument which as you guessed it, will be passed to the .catch handler.
When the promise resolve’s successfully, we use the .then handler to handle that state, and what happens is the string value passed to the resolve will be assigned to the value argument in .then which is then logged to the console.
Same thing happens when the promise fails and we want to handle that error with .catch
Although this approach works well, JavaScript have a special syntax that we can use to write asynchronous code in an elegant way, which is async / await.
Let’s look at how we can implement it;
Async / await - wait for me please
Async / await, introduced in ES8(2017), is a special syntax that makes writing promise code elegant, easy to read and debug.
With async / await, we write synchronous-like code whiles the underlying behavior is asynchronous.
Unlike promises where you have to use .then, .catch handlers to handle the different states of the promise, you use the keywords await and async.
Before we implement this in JavaScript, let’s understand the meaning of this keywords first;
async - we use this keyword to make the function return a promise, note that any function that has the keyword async will always return a promise.
await - this keyword is written in front of a promise, it tells JavaScript to momentarily wait till the promise has resolved before resuming the execution.
code snippet;
In the above code snippet, we are making an api request to star wars api.
let’s understand each line.
Notice the async keyword, which always make a function return a promise, aside that, there’s another thing you should be aware of, we can only use the await keyword in a function which is defined with the async keyword.
fetch is a function that helps us make api request, and with every other api request, we don’t get the value immediately, we get a promise object, hence we tell JavaScript to momentarily wait for this promise to resolve (finish its execution completely) and assign the resulting value to the response variable. That is what the await keyword does.
response.json() is also an asynchronous operation, hence we use the await keyword to wait momentarily for its execution to finish and then pass the resulting value to the data variable which we then log to the console.
Previously, with promises, we use .catch to handle cases where the asynchronous operation failed, how then do we handle operations that can lead to errors when using async / await ?
well, with try…catch
code snippet;
The code is similar to the previous one, but with try catch block.
Basically, we are telling JavaScript to try and execute the code in the try{} block, and if any error occurs, the catch{} block handles that error, in this scenario, the error is just logged to the console. This is how you can handle errors when using async / await.
JavaScript and the browser
I made mention that JavaScript is single-threaded and I showed you ways you can implement asynchronous code in JavaScript.
But if it’s really single-threaded, how then are you able to implement asynchronous code ?
What is really going on ?
Well, the runtime of JavaScript is indeed single threaded, but the browser has more than just the runtime.
The browser has features like web apis, callback or task queue, event loops etc which when we utilise them, we are able to write asynchronous instructions.
Note that these features are different threads that we can use in our application.
As this article is aimed towards beginners, knowing this is enough for now, however if you want to further your knowledge on this concept, checkout this article.
Summary
We started by understanding what synchronous and asynchronous programming are, then we looked at ways we can implement asynchronous instructions which are the following;
Callback
Promises
Async / await
We looked at each of them and how they can be implemented in code.
We then concluded with an introduction to concurrency and event loops.
Thank you for reading this article, will be glad to receive any sort of feedback.
References: