Rowdy Coders Logo

Rowdy Coders

5 min read

Mastering JavaScript Promises: The Key to Asynchronous Programming

JavaScript promises are a cornerstone of modern web development, enabling efficient handling of asynchronous operations.

JavaScript promises are a cornerstone of modern web development, enabling efficient handling of asynchronous operations. This article will guide you through the essentials of JavaScript promises.

What is a Promise?#

A JavaScript promise is an object that represents the eventual completion (or failure) of an asynchronous operation and its resulting value. Promises are particularly useful for dealing with asynchronous tasks without getting bogged down in callback hell.

Let's say in the below snippet, we are faking an API call, and after 1sec we get the data. But as soon as the code snippet executes, it will return us an object { data: undefined }

VS Code
const apiCallData = new Promise((resolve, reject)=>{
    const dataFromAPI = [1, 2, 3]
    setTimeout(()=>{
        resolve(dataFromAPI);
    }, 1000);
});
 
apiCallData.then((apiData)=>{
   // Do any thing here
});

After some time (async time of 1 second), this Promise Object will be filled with data.

VS Code
{ data: [1, 2, 3] }

Now, once we have data in the Promise Object, the above callback(then) function will be called automatically with the data.

VS Code
apiCallData.then((apiData)=>{
   // Once we have data in the Promise Object, this will be executed.
   // Do any thing here
});

Promise Object#

Promise State: A promise has three states:

  • Pending: The initial state, neither fulfilled nor rejected.
  • Fulfilled: The operation was completed successfully.
  • Rejected: The operation failed.

Promise Result: response/ undefined

Basic Structure of Promise:#

Here's how you create a promise:

VS Code
const promise = new Promise((resolve, reject) => {
  // Asynchronous operation
  let success = true; // This is just a simulation
 
  if (success) {
    resolve("Operation was successful!");
  } else {
    reject("Operation failed.");
  }
});

Using Promises: then and catch#

To handle the result of a promise, you use the then method for success and the catch method for errors.

VS Code
promise
  .then((message) => {
    console.log(message); // Output: Operation was successful!
  })
  .catch((error) => {
    console.error(error); // This will run if the promise is rejected
  });

Chaining Promises#

Promises can be chained to handle multiple asynchronous operations in a sequence.

VS Code
const firstPromise = new Promise((resolve) => {
  setTimeout(() => {
    resolve("First promise resolved.");
  }, 1000);
});
 
firstPromise
  .then((message) => {
    console.log(message);
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve("Second promise resolved.");
      }, 1000);
    });
  })
  .then((message) => {
    console.log(message);
  })
  .catch((error) => {
    console.error(error);
  });

Handling Multiple Promises: Promise.all and Promise.race#

Promise.all: It takes an array of promises and returns a single promise that resolves when all of the promises in the array resolve, or rejects if any of the promises reject.

VS Code
const promise1 = Promise.resolve("Promise 1 resolved.");
const promise2 = Promise.resolve("Promise 2 resolved.");
const promise3 = Promise.resolve("Promise 3 resolved.");
 
Promise.all([promise1, promise2, promise3])
  .then((messages) => {
    console.log(messages); 
    // Output: [ "Promise 1 resolved.", "Promise 2 resolved.", "Promise 3 resolved." ]
  })
  .catch((error) => {
    console.error(error);
  });

Interviewers might ask to create a polyfill for this Promise.all method, this is one of the most asked interview questions.

Promise.race: It returns a promise that resolves or rejects as soon as one of the promises in the array resolves or rejects.

VS Code
const promise1 = new Promise((resolve) => {
  setTimeout(resolve, 100, "First promise resolved.");
});
const promise2 = new Promise((resolve) => {
  setTimeout(resolve, 200, "Second promise resolved.");
});
 
Promise.race([promise1, promise2])
  .then((message) => {
    console.log(message); 
    // Output: "First promise resolved."
  })
  .catch((error) => {
    console.error(error);
  });

Interviewers might ask to create a polyfill for this Promise.race method, This is one of the most asked interview questions.

Async/Await: Simplifying Promises#

The async and await keywords provide a more concise and readable way to work with promises.

Basic Usage#

An async function always returns a promise. The await keyword can only be used inside an async function and pauses the execution of the function until the promise resolves.

VS Code
async function fetchData() {
  try {
    let response = await fetch("https://jsonplaceholder.typicode.com/posts/1");
    let data = await response.json();
    console.log(data);
  } catch (error) {
    console.error("Error fetching data:", error);
  }
}
 
fetchData();

Error Handling with Async/Await#

Error handling with async/await is done using try and catch blocks.

VS Code
async function performAsyncTask() {
  try {
    let result = await someAsyncFunction();
    console.log(result);
  } catch (error) {
    console.error("Error:", error);
  }
}
 
performAsyncTask();

Differences Between Promises and Async/Await#

Promises#

  • Execution: It is asynchronous in nature, which means it won't wait till the promise is resolved/rejected. Once the promise is resolved then the "then" block will be executed.
  • Syntax: Promises use the then and catch methods to handle asynchronous operations.
  • Error Handling: Errors are handled using the catch method.

Async/Await#

  • Execution: It is synchronous in nature, which means it will wait till the promise is resolved/rejected. The next code will be executed after the promise is resolved/rejected.
  • Syntax: Uses the async keyword to declare an asynchronous function and the await keyword to wait for a promise to resolve.
  • Error Handling: Errors are handled using try and catch blocks, making the code more similar to synchronous code.

Conclusion#

Promises and async/await are powerful tools in JavaScript that simplify handling asynchronous operations. By understanding and utilizing these concepts, you can write more readable and maintainable code. Whether you're fetching data from an API or performing complex asynchronous tasks, promises and async/await make your life as a developer easier and your code more efficient.

Thanks for reading!

Back to articles