Read more

Canceling promises

Henning Koch
December 29, 2018Software engineer at makandra GmbH

The standard way to abort async code is that your function takes a AbortSignal Show archive.org snapshot { signal } property. The caller can use this signal to send an abort request to your function. Upon receiving the request, your function should reject its promise with an error.

Illustration UI/UX Design

UI/UX Design by makandra brand

We make sure that your target audience has the best possible experience with your digital product. You get:

  • Design tailored to your audience
  • Proven processes customized to your needs
  • An expert team of experienced designers
Read more Show archive.org snapshot

Async browser functions like fetch() reject their promises with a new DOMException('Message here', 'AbortError') when canceled.

This already has good browser support and can be polyfilled on older browsers.

Example

Here is an async function countDown(). It returns a promise that will be fulfilled after the given number of seconds:

function countDown(seconds) {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, seconds * 1000)  
  })
}

Here is how you would use it:

countDown(10).then(() => console.log("10 seconds have past"))

// prints "10 seconds have past" after 10 seconds

Making countDown() abortable

Here is a variant of countDown() that may be canceled by the caller before the time has elapsed:

function countDown(seconds, options = {}) {
  return new Promise((resolve, reject) => {
    if (options.signal) {
      options.signal.addEventListener('abort', (event) => {
        reject(new DOMException('User aborted countdown', 'AbortError'))
      })
    }
  
    setTimeout(resolve, seconds * 1000)  
  })
}

You use it by passing an AbortSignal as a { signal } option and abort it manually by using an AbortController Show archive.org snapshot :

let controller = new AbortController()

countDown(10, { signal: controller.signal }).then(
  () => console.log("10 seconds have past"),
  (reason) => console.log("Countdown failed:", reason)
)

controller.abort()

/* prints "Coundown failed: User aborted countdown" in the next microtask */

Note that throwing a DOMException Show archive.org snapshot will guarantee combability with how the browser's API deals with promise abortion.

Posted by Henning Koch to makandra dev (2018-12-29 06:01)