Asynchronous JavaScript: Callbacks, Promises and Async/Await

Understanding Asynchronous JavaScript

Shamoda Jayasekara
Conceptual Viewpoint
5 min readMar 7, 2021

--

Let’s first understand the difference between synchronous and asynchronous. Synchronous operations of JavaScript execute one at a time. This means no matter how long the current operation takes, subsequent processes won’t start until the previous one is completed. Asynchronous operations run at the same time as other synchronous operations and then completes at some point in the future. The best example of an asynchronous operation is an API call. It may take few seconds for the data to be returned from the server. But our application will not freeze while it’s waiting for the data of the API call, it will continue the execution of other operations while waiting.

Operations in JavaScript are normally synchronous because JavaScript is a single-threaded language. It executes one operation at a time from top to bottom. But using callbacks, promises and async/await we can perform asynchronous JavaScript operations without blocking the main thread.

Well, let’s dive in!!! 😉

Callbacks

When a function accepts another function as an argument, this argument is known as a callback function. When the first function is executed, it will execute the second function. The callback function may be a named or an anonymous function. Here is an example,👇

Output: Hello John!

Multiple functions can be created independently and used as callbacks. But these will create a multi-level function and when you have too many of these nested functions the code becomes harder to read. It literally, impossible 😵This is known as Callback Hell. Look!!! 👇😬

So, you can see how confusing it is to pass each function as a callback. Callback functions are useful for short asynchronous operations. But when we are working with large sets of functions callback functions are not considered to be the best practice. Because of that, promises are introduced to simplify the same thing.

Promises

A promise represents the eventual completion or failure of an asynchronous operation and its resulting value. It is like a placeholder for a value that we are waiting on.

So, a promise is exactly what it sounds like. 😄 It is a promise to do something if some conditions are satisfied otherwise it won’t. With promises, we can differ the execution of a code block until an asynchronous operation is completed. This way other operations can keep executing without any interruption.

A promise can have 3 states,

· Pending
· Fulfilled
· Rejected

When the promise is pending, JavaScript continues code execution. This way the promise or the value that we are waiting on does not cause our program to freeze. Eventually, the promise state will change into either fulfilled or rejected. Then JavaScript goes back to that code block to execute the appropriate operations.

Let’s take a simple example.

We created a variable and assigned it to a new Promise. Promise accepts a function with two parameters (callbacks) called resolve and reject. Then, within our new promise, we can execute our asynchronous function. It may be an API call, downloading a file, or any other operation which will take some time.

After that, we can determine we should resolve or reject the promise depending on the success or failure of our asynchronous operation.

Well, we have created our promise and now let’s execute it.

Here, we called myPromise to initiate it and we used .then() method to look for the promise to enter the fulfilled state. It accepts a function that receives the resolved value from the resolve method. Inside .then() method, we can do any operation with the results of our asynchronous function or the promise. 😊

After that, we can use .catch() to look for the promise to enter the rejected state. It also accepts a function that receives any errors from our reject method.

Promise.all() Vs Promise.race()

Well, Lot of time we have multiple promises that we need to run at the same time and then do something once they have all completed. In this case, we can use Promise.all(). It accepts an array of promises and it will return their results in an array once all of them completed their execution.

For some reason, you may have multiple promises, and all you care about the first one that finishes, the rest of them you want to discard. In that case, we can use Promise.race(). This is only going to return the results of the first promise which finishes.

Async/Await

The async/await is basically just syntactic sugar wrapped around promises which makes them easier to work with. First, let’s take an example.

We’ve used fetch API to retrieve a set of todos over the network and it will return us a promise object. Here, we used .then() to wait on the data to be returned. This is fine for simple requests, but when we are dealing with multiple promises, it can get a little bit confusing to determine when each line will get executed.

With async/await we can write JavaScript code that looks synchronous but it’s actually asynchronous. 😉 Now, let’s see how we can rewrite this fetch statement with async and await. The first thing that we need to do is wrap our asynchronous code in a function and add the async keyword before the function.

Above, within the function, we have created a response constant and used the await keyword before our promise. In this case, it’s our fetch statement. 😄 On the next line, we did the same thing. We are waiting for our response.json() to execute before executing the last line. Finally, on the last line, we are logging the JSON data. It will wait until the previous lines are complete with their execution.

So, you can see this is very logical and the way this is written is easy to understand. But remember, you cannot use the await keyword without the async keyword attached to its wrapper function. These keywords will only work together. The function can be a standard function, arrow function, or even an anonymous function that calls itself.

Well, understanding how promises and async/await work together can make your code cleaner and more logical. Hope you got something from this article. Thanks for reading. Cheers for now!!!

Happy Coding!!!

--

--