Promises

In this article, we will see how to use a promise to perform asynchronous tasks.

I. What is a Promise?

A Promise is a JavaScript object that helps us perform asynchronous tasks.

Examples of asynchronous tasks are sending AJAX requests and calling functions inside setTimeout or setInterval.

A Promise can be in one of three states: pending, resolved, or rejected.

  • Pending (the initial state): The operation still needs to be completed.
  • Fulfilled: The operation has been completed successfully, and the promise now has a resolved value.
  • Rejected: The operation has failed, and the promise has a reason for the failure.

While the value is not yet available, the Promise stays pending. Afterward, it transitions to one of the two states: resolved or rejected.

II. Create a Promise Object

To create a new Promise object, we use the new keyword:

const myPromise = new Promise((resolve, reject) => {

};);

The function has two parameters:

  • resolve(value): this function will be called when the promise completes.
  • reject(error): this function will be called when an error occurs.
graph LR; A["new Promise (state: pending, result: undefined)"] A --> |"resolve"| B["state: fulfilled; result: value"] A -->|"reject"| C["state: rejected; result: error"]

Example:

function api.getUser(username) {
  return new Promise((resolve, reject) => {
    // Send AJAX request
    http.get(`/users/${username}`, (err, result) => {
      // If there's error, we call reject()
      if (err) return reject(err);
      // Otherwise, use resolve() to return value
      resolve(result);
    });
  });
};

III. then() and catch()

We can decide what to do with the return value in the form of .then() and catch if there’s an error.

Promise to get data
  .then(We'll print it out)
  .catch(There's something wrong here)

Overall:

  • We use .then() with a success handler callback containing the logic for what should happen if a promise resolves.
  • We use .catch() with a failure handler callback containing the logic for what should happen if a promise rejects.

1. then syntax

promise.then(
  function (result) {
    /* handle a successful result */
  },
  function (error) {
    /* handle an error */
  }
);

Example 1:

function getUser(username) {
  return new Promise((resolve, reject) => {
    http.get(`/users/${username}`, (err, result) => {
      if (err) return reject(err);
      resolve(result);
    });
  });
};

const onSuccess = (user) => console.log(user);
const onError = (err) => console.error(error);

getUser("anna").then(onSuccess, onError);

.then(onSuccess, onError) has 2 functions:

  • onSuccess is called when a promise is completed
  • onError is called when there’s an error

Example 2:

let promise = new Promise(function (resolve, reject) {
  setTimeout(() => resolve("done!"), 1000);
});

promise.then(
  (result) => alert(result), // shows "done!" after 1s
  (error) => alert(error) // doesn't run
);
  • The first argument of .then runs when the promise is resolved and receives the result.
  • The second argument of .then runs when the promise is rejected and receives the error.

2. catch

.catch handles the error object. It’s only used when reject() is called, which means there’s an error.

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(Error("Promise Rejected Unconditionally."));
  }, 1000);
});

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

promise.catch((err) => {
  alert(err);
});

IV. Chain Multiple Promises

If we have a sequence of asynchronous tasks, we can use promises chaining.

We do this by chaining multiple .then() and .catch().

new Promise(function (resolve, reject) {
  setTimeout(() => resolve(1), 1000);
})
  .then(function (result) {
    alert(result); // 1
    return result * 2;
  })
  .then(function (result) {
    alert(result); // 2
    return result * 2;
  })
  .then(function (result) {
    alert(result); // 4
    return result * 2;
  });

V. Promise.all()

If we have several promises, we can use Promise.all() method to execute multiple promises in parallel.

The syntax:

let promise = Promise.all([...promises...]);

Promise.all takes an array of promises and returns a new promise.

Example 1

Promise.all([
  new Promise((resolve) => setTimeout(() => resolve(1), 3000)), // 1
  new Promise((resolve) => setTimeout(() => resolve(2), 2000)), // 2
  new Promise((resolve) => setTimeout(() => resolve(3), 1000)), // 3
]).then(alert); // 1,2,3 when promises are ready

Example 2

const promise1 = Promise.resolve("Hello");
const promise2 = new Promise((resolve, reject) => setTimeout(resolve, 3000, "Bye"));
const promise3 = fetch("https://api.com/users").then(res => res.json());

Promise.all([promise1, promise2, promise3]).then(values => console.log(values));

If any of the promises is rejected, the promise returned by Promise.all immediately rejected with that error.

VI. setTimeout()

setTimeout() is a function that delays the execution of a callback function.

Example 1:

setTimeout(() => {
  console.log("It's been 3 seconds");
}, 3000);

Example 2:

let promise = new Promise(function (resolve, reject) {
  // after 1 second, show the result is "done"
  setTimeout(() => resolve("done"), 1000);
});