JavaScript Promises

Imagine asking someone to marry you. Their answer is a promise.

A JavaScript promise also represents an answer that may not be ready yet, and it can end up in one of three states:

  • pending: the promise is waiting to settle ⏳
  • fulfilled: the promise completed successfully 😊
  • rejected: the promise failed 🥲

When you wait for a promise, you usually keep doing other work until the result is ready. That is the whole point: promises let your code handle results later without blocking the rest of the program.

Creating a promise

If you already know the result, you can create a settled promise immediately. Use Promise.resolve() for a fulfilled promise and Promise.reject() for a rejected one.

const password = Promise.resolve("123");
const authenticated = Promise.reject(new Error("Log in to continue"));

You can also create a promise that settles later using new Promise(...). The constructor takes a function with two parameters: resolve and reject.

function propose() {
  if (Math.random() < 0.5) {
    console.log('She said no');
    return Promise.reject(new Error("You're not lucky today 😪"));
  }

  console.log('She said yes');

  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (Math.random() < 0.5) {
        return reject(new Error('You cheated on me 🥹'));
      }

      resolve('Wow! Finally, we are married 👰');
    }, 2000);
  });
}

This example shows a promise that may reject immediately, or wait 2 seconds and then either reject or resolve.

Using promises

To handle a promise result, use .then() for success and .catch() for errors.

password.then(value => {
  console.log(value);
});

authenticated.catch(err => {
  console.error(err);
});

propose()
  .then((fulfilled) => {
    console.log(fulfilled);
  })
  .catch((rejected) => {
    console.error(rejected);
  });

Async / await

async / await is a cleaner syntax for working with promises. Here is the same propose example written with async/await:

async function propose() {
  if (Math.random() < 0.5) {
    console.log('She said no');
    throw new Error("You're not lucky today 😪");
  }

  console.log('She said yes');
  await delay(2000);

  if (Math.random() < 0.5) {
    throw new Error('You cheated on me 🥹');
  }

  return 'Wow! Finally, we are married 👰';
}

function delay(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

Then use try / catch to receive the result and handle any errors:

try {
  const result = await propose();
  console.log(result);
} catch (error) {
  console.error(error.message);
}

Note that await can only be used inside an async function. If you want to use it at the top level, you can wrap it in an immediately invoked async function. But in modern JavaScript environments, you can use await at the top level without needing to wrap it in an async function.

Note also that await will pause the execution of the async function until the promise settles, but it does not block the entire program.


Here are more resources to learn about promises: