Asynchronous
Tags: programming, node, javascript, asynchronous
Published: 2022-07-08 18:17:00

Lately, I forgot what's the reason of `async`/`await` existence. Why do we have to use these keywords? What is promise? What is asynchronous? Also, what is callback? Here, I write it all about down as my personal note.

**Synchronous code is executed line by line**. Each line of code waits for the previous line to finish. What if we have long-running operations block code execution? It might be cause blocking and unresponsive.

Thus, asynchronous exists to solve this problem! 
> Asynchronous code is executed after a task that runs in the background finishes.

To implement asynchronous code, we could use _callback functions_ and _promises_. A **callback function** is a function that passed as an argument to another function whereas **promise** is something that is achieved or completed in the future. 

By using callback function we don’t need to assign the result of an operation into a variable then check if its error or not, simply just invoke the callback function at that time.

Let us see the example codes below:
![controller](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hkrbpib60yt1ljfhlrhc.png)

![model](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/imdz5wvif525y1prh8fo.png)

As we see, there are two asynchronous callback-based methods. The first is `Model.getPokemons()` and the second is `pool.query()` which is 3rd party API. 

To get pokemon list from the database, `Model.getPokemons()` requires a callback function – conventionally written as `cb()` – that must be provided by the `Controller.getPokemons()`. Once the data fetching by `pool.query()` is failed then returns the error, the model could immediately call the function `cb()` by passing the error back to the controller. Then, the error could be forwarded to the client side. 

The `cb()` as if an event handler. It's like "Hey, Model! Here, I provide the `cb()`, just call it whenever you need – as you get the error or as the data is ready,"

After successfully got the pokemon list, what if we need to fetch another data inside the else block? There will be so many nested callback, will make a **callback hell** or **pyramid of doom**. That's painful code causes maintenance and reading the code hard and must handle the error repetitively – did in every nest. Those are the reason why most modern asynchronous APIs don't use callbacks anymore.

**Need to know**:
A callback function doesn't automatically make code asynchronous. For instance, built-in functions in JavaScript that require a callback function. Usually, an asynchronous callback-based code has this format `(err, value) => {}`.

![built-in fn js](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fjhjtnxkz7elbxmibuz1.png)

Callback-based API: 
`setTimeout(cb, number)`, 
`addEventListener(string, cb)`, _from `XMLHttpRequest()`_

Promise-based API:
`fetch()`, _modern version of `XMLHttpRequest()`_

---

## Promise (ES6)

![promise schenario](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rns4uz76wqd6x959osj5.png)

> Promise – the foundation of asynchronous programming in JavaScript – is an object and we use the promise constructor to initialize a promise.

![promise basic example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2t7mty5z0g9bbhnomzb0.png)

There are some instance methods of promise to handle the eventual success or failure of the operation:
`.then()` to handle the **fulfilled** / successful
`.catch()` to handle the **rejected** / failed
`.finally()` to handle the **settled** (fulfilled or rejected)

**All those three are methods of promise that return a promise**. Allowing you to chain calls to another promise method, an operation called _composition_. Also, **with promise chaining, avoiding ever-increasing levels of indentation** when we need to make consecutive asynchronous function calls by using `.then()`.

If a promise doesn’t call `.then()` or `.catch()`, it will always be _pending_ because those two methods accept / forward the return of the promise operation and allow us to know its _settled status_, whether is the promise operation successful or not.

However, because a promise passes a callback function, promise could encounter callback-hell as well, named _promise-hell_. It is caused of there is a new promise `.then()` of top promise. It’s a condition where an asynchronous operation depends on the result of previous asynchronous operation. Otherwise, we can use `Promise.all()`, `Promise.any()`, etc.

**Nice to know** 
Promisifying is a method from NodeJS to convert a callback-based to promise-based asynchronous function. `util.promisify(cb)` taking an `(err, value) => ...` callback as the last argument, and returns a version that returns promises.

---

##  **Async/await (ES8)**

We are not only just using an asynchronous promise-based API from a 3rd party. Instead of using the old way style promise constructor, we can make our own by using `async` keywords! 

> Async/await is built on promises

The `async` keyword gives you a simpler way to work with asynchronous promise-based code. **By adding `async` at the start of a function makes it an asynchronous function**. 

Inside an `async` function you can use the `await `keyword before a promise-returning function. This makes the code wait at that point until the promise is settled, at which point the fulfilled value of the promise is treated as a return value, or the rejected value is thrown. Presumably, `await` keyword behaves like `.then()` and `.catch()` at once!

> async function always return a promise
> only use await inside an async function

As seen code below, let's say we want to consume a promise-based 3rd party API named `checkOddNumber()`. We can handle the promise by using `.then()` `.catch()` `.finally()` or simply just using `async` `await` with `try...catch...finally`

![promise-based api](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7wqd9l6f9gfofjrzqlho.png)

![handling promise](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p0kq8ugzxil1i610smo3.png)

Keep in mind that just like a promise chain, `await` forces asynchronous operations to be completed in series – easier to express and **there will be no more nested callback or callback hell**. This is necessary if the result of the next operation depends on the result of the last one. 


---

**References:**
1. https://developer.mozilla.org/en-US/docs/Learn/JavaScript
2. https://nodejs.dev/learn/modern-asynchronous-javascript-with-async-and-await
3. https://nodejs.org/api/util.html#utilpromisifyoriginal
4. https://linuxhint.com/callback-promise-javascript-examples