Facebook Pixel
Step-by-Step Guide

How to Use Promises and Async Await in Node.js

A step-by-step guide on how to write clean asynchronous Node.js code using Promises and async await instead of callback hell.

Understand the Callback Hell Problem

Callbacks are the original way Node.js handled asynchronous operations. When multiple async operations depend on each other, you nest callbacks inside callbacks, creating deeply indented code that is difficult to read, debug, and maintain. This nesting pattern is called callback hell or the pyramid of doom.

Understand What a Promise Is

A Promise is an object that represents the eventual result of an asynchronous operation. It exists in one of three states: pending while the operation is in progress, fulfilled when it completed successfully with a value, or rejected when it failed with an error. A Promise can only transition from pending to either fulfilled or rejected, never back.

Create a Promise

Construct a Promise by calling new Promise and passing an executor function with two parameters: resolve and reject. Inside the executor, perform your async operation. Call resolve with the result value when the operation succeeds. Call reject with an Error object when it fails. The executor runs immediately and synchronously.

Consume Promises with then and catch

Chain a then method on a Promise to handle the fulfilled value. Chain a catch method to handle rejection. Both methods return new Promises, allowing you to chain multiple async operations sequentially. Each then receives the resolved value of the previous Promise, creating a flat chain instead of nested callbacks.

Use Promise.all for Parallel Operations

When you have multiple independent async operations that do not depend on each other, run them in parallel using Promise.all. Pass an array of Promises and it returns a single Promise that resolves when all of them resolve, with an array of their results in the same order. If any single Promise rejects, Promise.all immediately rejects.

Use Async Await for Cleaner Syntax

Mark a function with the async keyword to enable await inside it. Use the await keyword before any Promise to pause execution of that function until the Promise settles. The function resumes with the resolved value. The surrounding code continues executing because async functions return Promises themselves and do not block the Event Loop.

Handle Errors with Try Catch in Async Functions

Wrap await calls inside a try-catch block to handle rejections. If an awaited Promise rejects, control jumps to the catch block with the error. This gives you the same error handling structure as synchronous code, making async code much easier to reason about compared to chaining catch methods on every Promise.

Avoid Common Async Await Mistakes

Never use await inside a forEach loop because forEach does not wait for async callbacks. Use a for-of loop instead when you need sequential execution. Avoid awaiting inside a loop when operations are independent, as this runs them sequentially and is slower than using Promise.all. Also always handle errors either with try-catch or by attaching a catch to the returned Promise.

Ready to master this completely?

Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.

Please Login.
Please Login.