13

I've been using the new fetch API instead of the old XMLHttpRequest

It is great but I am missing one crucial function, xhr.abort().

I can't find any information about that functionality for fetch.

Thanks.

UPDATE: hacky workaround for aborting fetch https://github.com/Morantron/poor-mans-cancelable-fetch

Basically you start the fetch in a web worker and cancel the web worker to abort the fetch

Royi Mindel
  • 1,258
  • 12
  • 35
  • 1
    That's because you can't cancel a fetch :( See: https://github.com/tc39/proposal-cancelable-promises/issues/70 https://github.com/whatwg/fetch/issues/27 So if you really need to abort the request, stick with XHR – Pimmol Feb 02 '17 at 07:57
  • 5
    Possible duplicate of [How do I cancel an HTTP fetch() request?](https://stackoverflow.com/questions/31061838/how-do-i-cancel-an-http-fetch-request) – spro May 30 '17 at 00:56
  • The workaround seems overkill, I would better shim the fetch then add the missing functionality – pdem Aug 23 '17 at 08:45
  • From Google's developer site: [Abortable fetch](https://developers.google.com/web/updates/2017/09/abortable-fetch) – vsync Oct 04 '18 at 11:19
  • Thanks for the update! Although it means you need to create and keep an AbortController for each fetch you want the ability to abort (if you are ok with aborting a group of fetches you’ll need less) and after each fetch to destroy the corresponding saved controller - by no means a perfect solution but better than the workaround – Royi Mindel Oct 04 '18 at 12:18

3 Answers3

15

Its still an open issue All relevant discussion can be found here

https://github.com/whatwg/fetch/issues/447 :(

Parth Ghiya
  • 6,929
  • 2
  • 30
  • 37
6

It's possible to abort fetch via AbortController:

export function cancelableFetch(reqInfo, reqInit) {
  var abortController = new AbortController();
  var signal = abortController.signal;
  var cancel = abortController.abort.bind(abortController);

  var wrapResult = function (result) {
    if (result instanceof Promise) {
      var promise = result;
      promise.then = function (onfulfilled, onrejected) {
        var nativeThenResult = Object.getPrototypeOf(this).then.call(this, onfulfilled, onrejected);
        return wrapResult(nativeThenResult);
      }
      promise.cancel = cancel;
    }
    return result;
  }

  var req = window.fetch(reqInfo, Object.assign({signal: signal}, reqInit));
  return wrapResult(req);
}

Usage example:

var req = cancelableFetch("/api/config")
  .then(res => res.json())
  .catch(err => {
    if (err.code === DOMException.ABORT_ERR) {
      console.log('Request canceled.')
    }
    else {
      // handle error
    }
  });

setTimeout(() => req.cancel(), 2000);

Links:

  1. https://developers.google.com/web/updates/2017/09/abortable-fetch
  2. https://developer.mozilla.org/en-US/docs/Web/API/AbortController
ixrock
  • 2,870
  • 2
  • 13
  • 7
3

I typically use something like this, similar to @ixrock.

// Fetch and return the promise with the abort controller as controller property
function fetchWithController(input, init) {
  // create the controller
  let controller = new AbortController()
  // use the signal to hookup the controller to the fetch request
  let signal = controller.signal
  // extend arguments
  init = Object.assign({signal}, init)
  // call the fetch request
  let promise = fetch(input, init)
  // attach the controller
  promise.controller = controller
  return promise
}

and then replace a normal fetch with

let promise = fetchWithController('/')
promise.controller.abort()
SiggyF
  • 22,088
  • 8
  • 43
  • 57