DEV Community

Dita Larasati
Dita Larasati

Posted on • Updated on

Asynchronous

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

model

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

Callback-based API:
setTimeout(cb, number),
addEventListener(string, cb), from XMLHttpRequest()

Promise-based API:
fetch(), modern version of XMLHttpRequest()


Promise (ES6)

promise schenario

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

promise basic example

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 awaitkeyword 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

handling promise

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

Top comments (0)