Promises and Why Async/Await Wins the Battle

Asynchronous functions are both good and bad in JavaScript. The good news is that asynchronous functions are non-blocking and therefore fast – especially in the context of Node.js. The downside is that handling asynchronous functions can be cumbersome, because sometimes you have to wait for a function to complete before you can get a “callback” before the next execution.

There are a few ways to take advantage of asynchronous function calls and properly handle their execution, but one is far superior to the others (Spoiler: it is Async/Await). In this article, you will learn the ins and outs of using Promises and Async/Await, and how we compare them.

Promises vs. Callbacks

As a JavaScript or Node.js developer, it’s important to understand the difference between Promises and Callbacks and how they work together.

There are small but important differences. At the core of each Promise, there is a Callback that resolves some data (or errors) that will be called into the Promise.

Callback handler:

catch
reject()
promise
reject()
"Catch"
done()

Promises

Promise offers a simpler alternative to the traditional callback-based approach for performing, composing, and managing asynchronous operations. They also allow you to handle asynchronous errors using methods like synchronous try/catch.

Promises also provide three unique states:

  1. PendingpromiseThe result of is not yet determined because the asynchronous operation that will produce its result has not yet completed.
  2. Fulfilled– The asynchronous operation is complete, andpromiseHave a value.
  3. Rejected– Asynchronous operation failed.promiseIt will never happen. In the state of being rejected,promiseThere is areasonYou can indicate why the operation failed.

When a promise is in the pending state, it can switch to the fulfilled or Rejected state. However, once the promise is fulfilled or rejected, it will never transition to any other state and its value or failure reason will not change.

Faults 👎

One thing Promise doesn’t do is address the so-called “callback hell.” The one thing promises don’t do is solve what is called “callback hell”, Which is really just a series of nested function calls.), “callback hell” is actually a series of nested function calls. Of course, it doesn’t matter for one call. But for multiple calls, your code will be hard to read and maintain.

Loop in Promises 🎡

To avoid deep nested callbacks using JavaScript, suppose you could simply traverse Promises, return the result to an object or array, and stop when done. Unfortunately, this is not easy; Due to the asynchronous nature of JavaScript, if you loop through each Promise, the “done” event is not called when the code completes.

The correct way to handle this is to use promise.all (). This function waits for all of Fulfillments (or the first rejection) before it’s marked as completed.

Error handling 💣

Error handling with multiple nested Promise calls is like driving a blindfolded car. Good luck finding out which Promise made the mistake. Your best option is to remove the catch() method entirely and choose to add a global error handler, as follows:

Browser:

Node.js

Pay attention to
catch()

Async/Await? 🤔

Async/Await allows us to write asynchronous JavaScript that looks synchronous. In the previous sections of this article, you learned about Promises – it was supposed to simplify asynchronous flows and avoid callback hell, but it didn’t.

Call back to hell? 🔥

Callback-hell is a term used to describe the following scenarios:

Note: For example, this is an API call that gets 4 specific users from an array.

This code is ugly and takes up a lot of space. Async/Await is the latest and greatest thing about JavaScript that allows us not only to avoid callback hell, but also to ensure that our code is clean and errors are caught correctly. What I find most fascinating about Async/Await is that it is built on Promises (non-blocking, etc.) and allows code to be readable and read as if it were synchronous. That’s the point.

Note: Here is an example of a set of API calls to retrieve four users from an array, more than half the lines:

Since Async/Await is built on Promises, you can even use promise.all () with the keyword Await:

Pay attention to
Async/await
await

How do I start using Async/Await? 💻

Using Async/Await is very easy to understand and use. In fact, it’s available natively in the latest versions of Node.js, and it’s rapidly moving into browsers. Now, if you want to use it on the client side, you need to use Babel.

Asynchronous Async

Let’s start with the async keyword. It can be placed before function as follows:

Waiting to Await

The keyword await causes JavaScript to wait for the promise to continue and return its result. As follows:

Why Async/Await is better? 😁

Now that we’ve seen a lot about Promises and Async/Await have to offer, let’s review why Stream thinks Async/Await is the best choice for a code base.

  1. Async/AwaitAllows for fewer lines of code, fewer inputs, and fewer errors, providing a clean code base. Finally, it makes complex nested code readable again.
  2. usetry/catchHandling errors (in one place, not in each call)
  3. The error stack is meaningful, not fromPromisesFuzzy errors received, they are large and difficult to locate where the error occurred. Most importantly, the error points to the function where the error occurred.

Final thoughts 📃

Async/Await is arguably one of the most powerful features added to JavaScript in the last few years.

It took less than a day to understand the syntax and see how bad our code base is at this. It took about two days in total to convert all of our Promise-based code to Async/Await, which is actually a complete rewrite – just to show that less code is needed when using Async/Await.