DEV Community

Jan Küster 🔥
Jan Küster 🔥

Posted on

4 2

Create a JavaScript Promise with timeout

I found a few examples on the web that let Promises run with a timeout:

Both were already good ideas but I wanted some more control of their behaviour and therefore I want to share my modified version.

Code

const defaultMessage = 'promise.timedOut'

/**
 * Lets a promise race against a timeout. If the promise settles before the timeout then it will
 * be the one to use (no matter, whether it has been resolved or rejected).
 *
 * Otherwise the timeout promise will be used to either resolve to a message
 * or reject an error, depending on the used options.
 *
 * @param promise {Promise} the promise to race against the timeout
 * @param timeout {number=}  optional number of milliseconds until timeout, defaults to 1000ms / 1 sec
 * @param throwIfTimedOut {boolean=} optional flag to either reject (if true) or resolve (if false), defaults to false
 * @param message {string=} optional message to be resolved/rejected on timeout, defaults to 'promise.timedOut'
 * @return {Promise<Awaited<unknown>>}
 */
export const createTimedPromise = (promise, { timeout = 1000, throwIfTimedOut = false, message, details } = {}) => {
  let timeOut = undefined

  const race = Promise.race([
    promise,
    new Promise((resolve, reject) => {
      timeOut = setTimeout(() => {
        if (throwIfTimedOut) {
          const error = new Error(message || defaultMessage)
          // I often like to attach contextual information to errors.
          // This is up to you, whether to do this or not
          error.details = details
          return reject(error)
        }
        else {
          return resolve(message || defaultMessage)
        }
      }, timeout)
    })
  ])

  // always clear timeout to prevent weird behaviour
  race.finally(() => clearTimeout(timeOut))

  return race
}
Enter fullscreen mode Exit fullscreen mode

Usage

// all default
await createTimedPromise(new Promise((resolve, reject) => { ... }))

// custom timeout
await createTimedPromise(new Promise((resolve, reject) => { ... }), { timeout: 500 })

// reject if timedout
await createTimedPromise(new Promise((resolve, reject) => { ... }), { throwIfTimedOut: true })

// additional context
await createTimedPromise(new Promise((resolve, reject) => { ... }), { message: 'you lost', details: { foo: 'bar' } })
Enter fullscreen mode Exit fullscreen mode

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

Top comments (0)

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay