Let's sync our mind around async in javaScript 🎉
Tags: javascript, webdev
Published: 2021-06-08 15:34:58

As we all know javaScript is single threaded, which means it can do one thing at any given time.This means that developers can focus writing code without worrying about multi-threaded issues.The problem with multi-threaded architecture is that developer has to know the order of execution of every code block that is waiting to be executed in different threads, this is not an issue in single threaded architecture because there is only one thread to worry about.However, in single threaded architecture executing long running tasks like network call will block the main thread.This is a bad user experience and this is where javaScript's asynchronous programming comes into picture.

![whats that Gif](https://media.giphy.com/media/9uIjYTJCtMnHsMpbHW/giphy.gif)

Asynchronous programming is a way to take a long running tasks away from normal code execution flow and showing the result of such tasks once they are done.This can be achieved by **callbacks**, **promises** or **Async/Await** in javaScript.

## Prerequisites
✔ You should be familiar with basic workings of javaScript like functions, conditional statements and so on. 
✔ No need to be familiar with asynchronous mechanisms like **promises**.

### Callbacks ✨
In this section, we will be learning about callbacks to handle asychronous operations.Callbacks are nothing but functions that get run once asynchronous code is finished executing.Let's look at it with solid example.

```javascript

function getSinger(id, callback) {
  setTimeout(() => {
    console.log('getting singer info from the database...')
    callback(singer)
   }, 2000)

getSinger(1, (singer) => {
  console.log('Singer', singer)
})

```
In the above code, we are declaring a function called **getSinger** which takes *id* and *callback* function as arguments.In the body of the getSinger function, we are calling javaScript's built in function called setTimeout to simulate network call to fetch the data from the database.After 2000ms,setTimeout function calls the callback function with **singer** data.
While calling getSinger function we are receiving singer data and then console logging it.That's it😎.

### Issues with callbacks
The callback pattern quickly becomes harder to read and maintain once nested callbacks are introduced. This is known as **"callback hell"**. Let me show with a quick example.

```javascript

function getSinger(id, callback) {
  setTimeout(() => {
    console.log('getting singer info from the database...')
    callback(singer)
   }, 2000)

getSongsList(singerName, callback) {
  setTimeout(() => {
    console.log('getting songs list info from the database...')
    callback(songsList)
   }, 2000)
}

getSinger(1, (singer) => {
  const singerName = singer.name
  getSongsList(singerName, (songsList) => {
    console.log(songsList)
})

```

In the above code, we have added **getSongsList** function which takes in *singerName* and a *callback* function as arguments.After setTimeout function finish running in 2000ms, the callback is called with songsList data.Finally, getSongsList is called inside getSinger's callback and then songsList data is printed to the console.

### Promises✨
Promises are nothing but objects that hold the eventual result of an asynchronous operation.It can have three possible states. 
* **Pending**: In this state the promise kickstarts an asychronous operation.
* **Resolved**: In this state the asynchronous operation is completed with a result.
* **Rejected**: In this state the asynchronous operation is completed with an error.

```javascript

// resolve state demo
const promise = new Promise((resolve, reject) => {
        // do some async work
         resolve(result)
})

promise.then(result => console.log(result))

//reject state demo
const promise = new Promise((resolve, reject) => {
        // do some async work
        // resolve(result)
           reject(new Error('message'))
})

promise
      .then(result => console.log(result))
      .catch(error => console.log(error.message))

```
First we initialize promise object with new keyword. A promise object runs async operation and calls resolve function if there is result else it calls reject function if there is error.
Later, **then** handler is used to access result and catch handler is used access error.

Now let's modify our callback example to use Promise.

```javascript

function getSinger(id) {
 return new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log('getting singer info from the database...')
    resolve(singer)
   }, 2000)
})
}

getSongsList(singerName){
  return new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log('getting songs list info from the database...')
    resolve(songsList)
   }, 2000)
  })
}

getSinger(1)
     .then(singer => getSongsList(singer.name))
     .then(songsList => console.log(songsList))

```
In the above code, we are returning a promise from both getSinger and getSongsList functions.Both goes to resolved state.When promise is consumed, we chain two **then** handlers.This is cleaner syntax than callbacks.

### Async/Await ✨
Async/Await is a new feature in javaScript that let's you write asynchronous code in a synchronous way. Whenever there is a function that returns a promise, you can **await** that result and then wrap that code with **async** modifier.Let's look at the example.

```javascript

function getSinger(id) {
 return new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log('getting singer info from the database...')
    resolve(singer)
   }, 2000)
})
}

getSongsList(singerName){
  return new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log('getting songs list info from the database...')
    resolve(songsList)
   }, 2000)
  })
}

async function displaySongsList() {
   try {
     const singer = await getSinger(1)
     const songsList = await getSongsList(singer.name)
     console.log(songsList)
  }
  catch(error){
   console.log(error.message)
    }
  }

displaySongsList()

```

We declare a function called displaySongsList, and then wrap await statements in **try** block, if an error occurs then it is handled by **catch** block. That's it.🎉🎉

## Conclusion

First we understood what asynchronous operation in javaScript is.Then we explored how **callbacks** comes to the picture while dealing with async operations.Next we looked at **Promises** as better alternative to callbacks. Finally we looked at **Async/Await** which builds upon Promises.