Node.js Promises vs Async/Await: Which one is Better

Node.js is an open-source cross-platform JavaScript runtime built on Chrome’s V8 JavaScript engine. Node.js uses the process model instead of the traditional web server model, which makes it suṀper useful for web development. It allows developers to use JavaScript to create server-side applications that can handle multiple requests simultaneously without any clash between them, which makes it ideal for building real-time, data-intensive applications.

In this tutorial, we have briefly introduced Node.js Promises and Async/Await. Also, you’ll get to know which one is better. Before diving deep into this let’s get a sight of synchronous and asynchronous programming.

Synchronous Programming in Node.js

In synchronous programming, the statements are executed in a linear order. Only a single statement is executed at a time. i.e., if a statement takes a long time to complete it will block the entire flow of the code. e.g., if we use the “window.alert()” method in JavaScript it will block the rest of the code until a key is pressed.

Asynchronous Programming in Node.js

It is a technique that allows us to execute the rest of the code even if one of the statements is still not executed. In asynchronous programming, the code is not executed in linear order. It allows the program to handle multiple operations simultaneously which makes it more efficient. e.g., if we use the “setTimeInterval()” method in a JavaScript code, it will get executed when the condition is satisfied but it will not block the flow of the code. The rest of the statements will still get executed.

Understanding Promises in Node.js

Promises in Node.js are used to bring asynchronous operations to life. With the help of promises, we can handle long-running operations without blocking the main body execution. A promise represents a value that may not be available at the time of execution but in the future, it can have three possible states.

  • Fulfilled
  • Rejected
  • Pending

Promises are like real-life promises. e.g., I can give a promise that I will write the best article on “Node.js Promises and Async/Await”, Now either I will fulfil my promise by writing the best article or I will not write the best article or maybe I will still be writing the article I claimed to be best.

The same way Node.js Promises works. Either they are fulfilled, rejected, or pending.

const myPromise = new Promise((resolve, reject) => {
  if (/* Success  */) {
    resolve(/* Result */);
  } else {
    reject(/* Error */);
  }
});

While working with promises we use the “.then()” method to handle the successful completion of the promise whereas the “.catch()” method is used to handle the errors. Promises provide a very flexible handy way to manage asynchronous operations in Node.js which makes it really easy to write manageable and scalable code.

myPromise.then((result) => {
  // Handle the successful execution of the promise with the result
}).catch((error) => {
  // Handle errors that occurred 
});

Drawbacks of Promises in Node.js

Although Promises are a really great and flexible way to handle asynchronous operations. They do have some drawbacks:

Callback Hell

Though Promises reduce the level of callback nesting to a large extent, it still leads to a chain of “.then()” calls which are hard to manage. This often occurs when we are dealing with highly complex and big asynchronous workflows.

doSomething()
  .then(function(result1) {
    doSomethingElse(result1)
      .then(function(result2) {
        doAnotherThing(result2)
          .then(function(result3) {
            console.log(result3);
          })
          .catch(function(error) {
            console.error(error);
          });
      })
      .catch(function(error) {
        console.error(error);
      });
  })
  .catch(function(error) {
    console.error(error);
  });

Wasted Resources

While working with promises once a promise is invoked it cannot be cancelled. i.e., if we have a long-running operation that we don’t require anymore we cannot cancel its execution. This makes it difficult to manage big and complex workflows and leads to the wastage of resources.

Error Handling

Promises are great while working with asynchronous operations, but it doesn’t solve all the problems. It doesn’t have a proper mechanism for handling errors that occur during the execution.

Difficult to Debug

While working with promises if a promise throws an error it’s really hard to figure out from where the error originated. This happens particularly when an error is thrown by a complex chain of promises.

Adds unnecessary complexity

Promises are great when we are working with long-running complex asynchronous operations but when it comes to working with simple code promises simply add unnecessary complexity to the code.

Understanding Async/Await in Node.js

Async/Await is another way of handling asynchronous operations in Node.js. It makes it easier to write asynchronous code in Node.js. It makes the asynchronous code look like synchronous code which makes it easier to read and maintain.

While working with Async/Await the asynchronous functions are marked with the “async” keyword. These functions return a “Promise object” which is resolved with the “await” keyword.

async function fetchData() {
  const response = await fetch('https://api.example.com/data');
  const data = await response.json();
  return data;
}

In this code, the “fetchData” function is an “asynchronous” function that returns a Promise object. Inside the function, the “fetch” method is used to make a network request to an API. The “await” keyword is used to wait for the response to be returned before continuing. Once the response is returned, the “JSON” method is called on the response object, again using the await keyword to wait for the parsing of the response body to be completed.

Async/Await is a powerful feature that can make asynchronous code easier to write, read, and maintain. It can also make it easier to handle errors in asynchronous code

Difference Between Promises and Async/Await

Promises and Async/Await, both are techniques to handle asynchronous operations in Node.js. There is no particular answer as to which one is better. The choice between the two techniques largely depends on use cases and personal preferences.

Yet as “Async/Await” is a fairly new technology and it works well with both simple and complex JavaScript code and is really easy to read and maintain, the new generation of developers prefers using “Async/Await” over “Promises“.

Advantages of Async/Await Over Promises

Below are some reasons why Async/Await is preferred over Promises.

Easier to Read, Write and Maintain

While working with Async/Await we are able to give a synchronous-like look to our asynchronous code. Which is ultimately easier to read, write and maintain. It also avoids the “Pyramid of doom” and “Callback Hell” which often occurs due to complex promise chains.

Error Handling

With Async/Await error handling becomes really easy. We can use “try/catch” to handle errors in a synchronous way. Which makes the code easier to understand.

Compatibility

Async/Await works with both synchronous and asynchronous code. This makes it relatively more flexible than Promises which is strictly for handling asynchronous code.

Debugging

Async/Await offers better debugging capabilities. We can use the debugger to check the code line by line as we do in asynchronous programming.

Summary

Node.js Promises and Async/Await make asynchronous programming possible. All modern web apps that use some API or JavaScript are incomplete without asynchronous programming. In this tutorial, we gave a brief introduction to synchronous programming, asynchronous programming, promises and async/await. We have also covered the advantage of async/await over promises in Node.js. Hope this tutorial helps.

References

https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous

Vikas Negi
Vikas Negi
Articles: 3