How to do Asynchronous Programming in JavaScript?

Featured on daily.dev
How to do Asynchronous Programming in JavaScript?

Do you know what is synchronous and asynchronous programming? Let's go through them first and explore different ways to do asynchronous programming in javascript.

First let's see what is Synchronous Programming in JavaScript

JavaScript is a single-threaded, synchronous, blocking language. That simply means that only one operation can be active at any given time.

Let's see a quick example -

image.png

In the above example, you can see the code is executed line by line,i.e., a single operation is performed by javascript at any given time. What if the function takes a long time? We will have to wait for the function to finish its operation and then move to the next line of operation. This is called code blocking. To solve this problem we have some Web APIs through which we can perform asynchronous operations in javascript.

Now let's understand Asynchronous Programming in JavaScript

Asynchronous programming allows you to perform operations without blocking the main thread. You can switch to another task before the previous one is completed in asynchronous operation, allowing you to handle many requests at once.

JavaScript is a synchronous language but with the help of Web APIs, Task Queues, and Event Loop it enables us to perform asynchronous operations. If you want to know more about Event Loop, I would suggest going through this video.

Let's see a quick example -

image.png

In the above example, setTimeout is used to perform an asynchronous operation. setTimeout is one of the Web APIs which lets us do async tasks. As you can see, since there is a setTimeout in line 2, the program didn't wait there to finish that operation, instead, it went to the next line and executed the callback in setTimeout at last.

Ways to write non-blocking code

  • Callbacks
  • Promises
  • Async/await

6fu5b5.jpg

Callbacks

A callback is just a function that is handed into another function with the expectation that it will be invoked when the time comes. Callbacks were once the primary method of implementing asynchronous functions in JavaScript.

Let's see an example -

image.png

In the above example, a callback is passed to the getData function which gets executed after the setTimeout delay gets over. But callbacks can sometimes create problems as they can create callback hell.

Let's see what a callback hell looks like.

//callback hell
getUser(123, (user) => {
  console.log("User", user);
  getPosts(user.username, (posts) => {
    console.log(posts);
    getComments(posts[0], (comments) => {
      console.log(comments);
    }
})

To avoid callback hell, we have promises.

Promises

For providing the outcomes of asynchronous computation, Promises are an alternative to callbacks. They take more effort from asynchronous function implementors, but they provide significant advantages for users.

Creation of promise using promise constructor -

let promise = new Promise(function(resolve, reject) {
  // your code
resolve("resolved");
});

Here, resolve and reject are callbacks provided by JavaScript.

Promise states -

  1. Pending: Initial state of promise till execution is completed.
  2. Fulfilled: The promise-related activity was successful.
  3. Rejected: The promise-related activity was unsuccessful.
  4. Settled: Has been fulfilled or rejected.

Promises_in_JavaScript.webp

Consumers: These are functions that will receive the result or error and can be registered using methods -.then, .catch, and .finally. For results .then function is used and for error .catch function is used. The.finally function always runs when the promise is settled: be it resolved or rejected.

But how does it solve the problem of callback hell?

Multiple promises can be chained using the .then function.

// Replace Callback with Promises to avoid callback hell
getUser(1)
  .then(user => getPosts(user.username))
  .then(posts => getComments(posts[0]))
  .then(comments => console.log("Comments", comments))
  .catch(err => console.error(err.message));

Doesn't it look better and more readable than the callback hell? Even using arrow functions makes it more concise.

Async/await

Async/await is a special syntax to work with promise. It's simple to comprehend and use. We just have to add the async keyword before the function and it would mean that the function returns a promise. Then inside the function, we use await before the promise and assign the value received to a variable.

Let's see the same example which we saw in promise chaining.

async function displayComments() {
  try {
    const user = await getUser(123);
    const posts = await getPosts(user.username);
    const comments = await getComments(posts[0]);
    console.log(comments);
  } catch (err) {
    console.error(err.message);
  }
}

displayComments();

Async/await is just a more elegant syntax of getting the promise result than promise.then. And, it’s easier to read and write. In async/await we don't have the .catch function so we use try-catch to handle errors.

Note: await works only inside async functions.

Wrapping up

Some brief points that we covered:

  1. Synchronous and asynchronous programming
  2. Callbacks and callback hell
  3. Promises and async/await

Thanks for reading!! Give some reactions if you liked it. If you want to say something about the topic or give some feedback, write it down in the comments. Wanna connect with me or see my projects? Here's my portfolio link.

References