Hello everyone,

I'm trying to get a solid understanding of JavaScript Promises. I know they are used for asynchronous operations, but I'm finding it a bit tricky to grasp how they work under the hood and when exactly to use them. I've seen examples with `fetch`, but I'm curious about custom promise creation and handling different states (pending, fulfilled, rejected).

What are Promises?

A Promise is an object that represents the eventual completion (or failure) of an asynchronous operation and its resulting value. It's a placeholder for a value that is not necessarily known when the Promise is created.

Promise States

Creating a Custom Promise

Here's a basic example of how to create a Promise:


function delay(ms) {
  return new Promise((resolve, reject) => {
    if (ms < 0) {
      reject(new Error('Delay time cannot be negative'));
    } else {
      setTimeout(() => {
        resolve(`Operation completed after ${ms}ms`);
      }, ms);
    }
  });
}

// Example usage:
delay(2000)
  .then((message) => {
    console.log(message); // "Operation completed after 2000ms"
  })
  .catch((error) => {
    console.error('Error:', error.message);
  });

delay(-100)
  .then((message) => {
    console.log(message);
  })
  .catch((error) => {
    console.error('Error:', error.message); // "Error: Delay time cannot be negative"
  });
            

Chaining Promises

Promises can be chained together using `.then()` to handle sequential asynchronous operations.


fetch('/api/data/user/1')
  .then(response => {
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return response.json();
  })
  .then(userData => {
    console.log('User data:', userData);
    return fetch(`/api/data/posts/${userData.id}`);
  })
  .then(response => {
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return response.json();
  })
  .then(postData => {
    console.log('User posts:', postData);
  })
  .catch(error => {
    console.error('Fetching data failed:', error);
  });
            

Async/Await

The async and await keywords provide a more modern and readable way to work with Promises.


async function getUserAndPosts(userId) {
  try {
    const userResponse = await fetch(`/api/data/user/${userId}`);
    if (!userResponse.ok) {
      throw new Error(`HTTP error! status: ${userResponse.status}`);
    }
    const userData = await userResponse.json();
    console.log('User data:', userData);

    const postsResponse = await fetch(`/api/data/posts/${userData.id}`);
    if (!postsResponse.ok) {
      throw new Error(`HTTP error! status: ${postsResponse.status}`);
    }
    const postData = await postsResponse.json();
    console.log('User posts:', postData);

  } catch (error) {
    console.error('Fetching data failed:', error);
  }
}

getUserAndPosts(1);
            

Any tips or common pitfalls I should be aware of when working with Promises?