Skip to the content.

Using Promise

Promise<T> can be either pending or fulfilled or rejected. fulfilled and rejected are representing results.

Every promise should eventually be resolved or rejected

const promiseSample: Promise<number> = Promise.resolve(1);

Dummy result wrappers can be created directly

Promise.resolve(1);
Promise.reject(1);

Constructor

new <T>(executor: (
   resolve: (value?: T | PromiseLike<T>) => void,
   reject: (reason?: any) => void) => void
): Promise<T>;
new Promise<number>(
  (resolve: (data: number) => void, reject: (reason: any) => void) => {
    try {
      resolve(1 + 1);
    } catch (e) {
      reject(e);
    }
  }
);

Promise transforms callback approach into chaining of error or result handlers

import axios from "axios";
axios
  .get("/user", {
    params: {
      ID: 12345,
    },
  })
  .then((response) => {
    // process response
    console.log(response);
  })
  .catch((error) => {
    // process error
    console.log(error);
  })
  .then(() => {
    // always executed
  });

Chain calls

Promise.resolve(1)
  .then((result) => result + 1)
  .then((result) => {
    console.log(result); // 2
    return result;
  })
  .then((result) => result + 1)
  .then((result) => {
    console.log(result); // 3
    return result;
  });

Catching errors in one place for all then cases

Promise.resolve(1)
  .then((result) => result + 1)
  .then((result) => result / 0)
  .then((result) => result * 1)
  .catch((error) => {
    console.error(error);
  });

Catching expected errors in the middle of the processing

Promise.resolve(1)
  .then((result) => result / 0)
  .catch((error) => {
    // catch division by zero
    console.error(error);
    // it will be Promise.resolve(0)
    // so `.then` chaining could be used again
    return 0;
  })
  .then((result) => result + 1)
  .then((result) => result * 1);

Chaining promise functions

interface UserShape {
  userId: number;
  name: string;
}
const loadUser = (userId: number): Promise<UserShape> =>
  Promise.resolve({
    userId: 1,
    name: "Some user",
  });

const capitalizeUser = (user: UserShape): Promise<UserShape> =>
  Promise.resolve({
    ...user,
    name: user.name.toUpperCase(),
  });

const logUser = (user: UserShape): Promise<UserShape> => {
  console.log(user);
  return Promise.resolve(user);
};

const sendUser = (user: UserShape): Promise<any> => axios.post("url", user);

loadUser(42)
  .then(capitalizeUser)
  .then(logUser)
  .then(sendUser)
  .catch(console.error);

Transforming callback function into Promise based

const plusOneCallback = (
  value: number,
  cb: (err: Error | undefined, result: number) => void
) => cb(undefined, value + 1);

const plusOnePromise = (value: number) =>
  new Promise((resolve, reject) => {
    plusOneCallback(value, (error, data) => {
      if (error) {
        return reject(error);
      }
      resolve(data);
    });
  });

plusOnePromise(42).then(console.log);

Promise helper functions

Promise.all

Returns a single Promise that resolves to an array of the results of the input promises

It rejects immediately upon any of the input promises rejecting

const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = Promise.resolve(2);

Promise.all([promise1, promise2, promise3]).then((values) => {
  console.log(values); // [3, 42, 2]
});

Rejection in Promise.all()

const promise11 = Promise.resolve(3);
const promise22 = Promise.reject(42);
const promise33 = new Promise((resolve) => {
  setTimeout(() => resolve(100), 100);
});

Promise.all([promise11, promise22, promise33])
  .then((values) => {
    console.log(values);
  })
  .catch(console.error); // => 42

Promise.allSettled

Method returns a promise that resolves after all of the given promises have either fulfilled or rejected, with an array of objects that each describes the outcome of each promise.

You usually want to use .allSettled instead of .all

function settledExample() {
  const promise100 = Promise.resolve(3);
  const promise200 = new Promise((resolve, reject) => {
    setTimeout(() => reject(100), 100);
  });
  Promise.allSettled([promise100, promise200]).then((results) => {
    console.log(results);
    // [
    //   { status: 'fulfilled', value: 3 },
    //   { status: 'rejected', reason: 100 }
    // ]
    const finishedValues = results
      .filter((x) => x.status === "fulfilled")
      .map((x) => (x as PromiseFulfilledResult<number>).value);
    console.log(finishedValues); // [ 3 ]
  });
}
settledExample();

Promise.race

Method returns a promise that fulfills or rejects as soon as one of the promises in an iterable fulfills or rejects, with the value or reason from that promise.

function raceSample() {
  const apiCallSuccess = new Promise((res, rej) =>
    setTimeout(() => res("Done"), 100)
  );
  const apiCallFailure = new Promise((res, rej) =>
    setTimeout(() => rej("Error"), 100)
  );
  const timeoutPromise = (ms = 300) =>
    new Promise((res, rej) => setTimeout(rej, ms));

  const requestWithTimeout = <T>(request: Promise<T>, timeout = 300) =>
    Promise.race([timeoutPromise(timeout), request]);

  requestWithTimeout(apiCallSuccess).then(console.log);
  requestWithTimeout(apiCallFailure).catch(console.error);
}
raceSample();

More info

Check MDN docs