JavaScript Promises

In this tutorial, you will learn how JavaScript Promises work and how they simplify asynchronous code. You will understand how to create and use Promises, handle results using .then() and .catch(), run tasks in sequence and in parallel, and simplify logic using async and await. Real examples using API calls will help you apply these concepts in practical scenarios. By the end, you'll know how to write cleaner, more maintainable code for asynchronous tasks.



What Is a JavaScript Promise?

JavaScript Promises provide a modern way to handle asynchronous operations such as fetching data from an API, reading files, or working with timers. A Promise is an object that represents a value that may be available now, in the future, or never. It starts in a pending state and then moves to either fulfilled when successful or rejected when failed. Instead of using nested callbacks, Promises allow you to write readable and structured code. You can handle the result or error using .then() and .catch(), or simplify it further using async and await.

Why Use Promises?

Promises help you:

  • Avoid nested callbacks (known as "callback hell").
  • Write cleaner asynchronous code with clear flow.
  • Handle errors in one place using .catch() or try...catch.
  • Work seamlessly with modern features like async/await.

Creating Promises

You create a Promise using the Promise constructor. Here's an example where a user checks access to a resource:

const checkAccess = new Promise((resolve, reject) => {
  const hasAccess = true; // simulate condition
  hasAccess
    ? resolve("Access granted")
    : reject("Access denied");
});

// Handle result
checkAccess
  .then(message => console.log(message))       // Output: Access granted
  .catch(error => console.error(error));

You can also handle this using async and await for simpler syntax:

async function verifyAccess() {
  try {
    const result = await checkAccess;
    console.log(result);
  } catch (error) {
    console.error(error);
  }
}

verifyAccess();

Making an API Call Using Promises

The fetch() function returns a Promise. Use .then() to handle the response and .catch() for errors. In this example, a user fetches her profile from a sample API:

fetch("https://jsonplaceholder.typicode.com/users/5")
  .then(response => response.json())
  .then(user => console.log("User:", user.name))  // Output: Chelsey Dietrich
  .catch(error => console.error("Fetch error:", error));

Chaining Promises

You can chain Promises by returning a new Promise inside .then(). Here, a user is fetched first, and then their posts are loaded:

function getUser() {
  return fetch("https://jsonplaceholder.typicode.com/users/7")
    .then(res => res.json());
}

function getPosts(userId) {
  return fetch(`https://jsonplaceholder.typicode.com/posts?userId=${userId}`)
    .then(res => res.json());
}

getUser()
  .then(user => {
    console.log("User:", user.name);         // Output: Kurtis Weissnat
    return getPosts(user.id);
  })
  .then(posts => {
    console.log("Post count:", posts.length);
  })
  .catch(error => console.error("Error:", error));

Running Promises in Parallel

Use Promise.all() to run multiple Promises at the same time. If any Promise fails, it returns an error immediately:

const productPromise = fetch("https://fakestoreapi.com/products/1").then(res => res.json());
const reviewPromise  = fetch("https://fakestoreapi.com/products/1/reviews").then(res => res.json());

Promise.all([productPromise, reviewPromise])
  .then(([product, reviews]) => {
    console.log("Product:", product.title);      // Output: Fjallraven - Foldsack No. 1 Backpack
    console.log("Review count:", reviews.length);
  })
  .catch(error => console.error("Error:", error));

If any Promise rejects, Promise.all() rejects immediately with that error.

Using async and await

You can simplify Promise handling using async and await. This keeps your code clean and avoids chaining multiple .then() calls. Here's an example that fetches comments:

async function showComments() {
  try {
    const response = await fetch("https://jsonplaceholder.typicode.com/comments?postId=3");
    const comments = await response.json();
    console.log("Comments loaded:", comments.length);
  } catch (error) {
    console.error("Failed to load comments:", error);
  }
}

showComments();

Error Handling Best Practices

Always attach .catch() to the end of your Promise chains or use try...catch blocks inside async functions. Handle errors gracefully and display helpful messages to users. If needed, implement retry logic to handle temporary failures like network issues.

Conclusion

In this tutorial, you learned how to use JavaScript Promises to manage asynchronous operations. You created Promises, handled results using .then() and .catch(), chained multiple operations, ran Promises in parallel using Promise.all(), and simplified syntax with async and await. Promises help you write clear, consistent, and error-resistant code when working with APIs and time-based tasks in JavaScript.



Found This Page Useful? Share It!
Get the Latest Tutorials and Updates
Join us on Telegram