How can I add a timeout to a promise in JavaScript?

JavaScript, Promise, Timeout, Class · Jun 12, 2021

Many times in the past I've found myself needing to add a timeout to a promise in JavaScript. setTimeout() is not exactly a perfect tool for the job, but it's easy enough to wrap it into a promise:

const awaitTimeout = delay =>
  new Promise(resolve => setTimeout(resolve, delay));

awaitTimeout(300).then(() => console.log('Hi'));
// Logs 'Hi' after 300ms

const f = async () => {
  await awaitTimeout(300);
  console.log('Hi');  // Logs 'Hi' after 300ms

There's nothing particularly complicated about this code sample, really. All it does is use the Promise constructor to wrap setTimeout() and resolve the promise after delay ms. This can be a useful tool when some code has to stall for a given amount of time.

In order to add a timeout to another promise, however, there are two additional needs this utility has to satisfy. The first one is allowing the timeout promise to reject instead of resolving when provided a reason as a second argument. The other one is to create a wrapper function which will add the timeout to the promise:

const awaitTimeout = (delay, reason) =>
  new Promise((resolve, reject) =>
      () => (reason === undefined ? resolve() : reject(reason)),

const wrapPromise = (promise, delay, reason) =>
  Promise.race([promise, awaitTimeout(delay, reason)]);

wrapPromise(fetch(''), 3000, {
  reason: 'Fetch timeout',
  .then(data => {
  .catch(data => console.log(`Failed with reason: ${data.reason}`));
// Will either log the `message` if `fetch` completes in under 3000ms
// or log an error message with the reason 'Fetch timeout' otherwise

As you can see in this example, reason is used to determine if the timeout promise will resolve or reject. awaitTimeout() is then used to create a new promise and passed to Promise.race() along with the other promise to create a timeout.

This implementation definitely works, but we can take it a couple steps further. An obvious improvement is the addition of a way to clear a timeout, which requires storing the ids of any active timeouts. This, along with the need to make this utility self-contained both make a great case for using a class:

class Timeout {
  constructor() {
    this.ids = [];

  set = (delay, reason) =>
    new Promise((resolve, reject) => {
      const id = setTimeout(() => {
        if (reason === undefined) resolve();
        else reject(reason);
      }, delay);

  wrap = (promise, delay, reason) =>
    Promise.race([promise, this.set(delay, reason)]);

  clear = (...ids) => {
    this.ids = this.ids.filter(id => {
      if (ids.includes(id)) {
        return false;
      return true;

const myFunc = async () => {
  const timeout = new Timeout();
  const timeout2 = new Timeout();
  timeout.set(6000).then(() => console.log('Hello'));
  timeout2.set(4000).then(() => console.log('Hi'));
    .wrap(fetch(''), 3000, {
      reason: 'Fetch timeout',
    .then(data => {
    .catch(data => console.log(`Failed with reason: ${data.reason}`))
    .finally(() => timeout.clear(...timeout.ids));
// Will either log the `message` or log a 'Fetch timeout' error after 3000ms
// The 6000ms timeout will be cleared before firing, so 'Hello' won't be logged
// The 4000ms timeout will not be cleared, so 'Hi' will be logged

Written by Angelos Chalaris

I'm Angelos Chalaris, a JavaScript software engineer, based in Athens, Greece. The best snippets from my coding adventures are published here to help others learn to code.

If you want to keep in touch, follow me on GitHub or Twitter.

More like this

  • JavaScript Promises

    JavaScript promises provide a modern and elegant way to to handle asynchronous operations. This snippet collection covers the basics of promises and how to use them in your code.

    Collection · 8 snippets

  • How can I implement a sleep function in JavaScript?

    Learn all the different ways you can implement a sleep() function in JavaScript.

    JavaScript, Date · Nov 6, 2021

  • Tip: The order of then and catch matters

    Messing up the order of chained then and catch methods in JavaScript promises can result in all sorts of problems. Here's a short primer on the subject.

    JavaScript, Function · Jun 12, 2021

  • Asynchronous JavaScript Cheat Sheet

    Learn everything you need to know about promises and asynchronous JavaScript with this handy cheatsheet.

    JavaScript, Function · Jun 12, 2021