What all this basically does is tries to turn fetch's AbortController mess with rejecting via "AbortError" to something more consistent, abstract and usable.
There are only 2 API differences from your usual fetch and promises:
- Promise now has 2 more fields: method
abort()
and asignal
field, which is theAbortController.signal
(can be used to manipulate abort events). - Promise constructor now accepts a different argument:
(resolve, reject, abort) => void
. Basically, it's a standard promise executor but with an additional function argument. AbortablePromise constructor can also accept any standard promise and convert it into an Abortable one.
Abortin the promise doesn't cancel the request. It just guarantees that the response will be ignored no matter what.
Example:
const a = new Abortable.Promise((resolve, reject, abort) => setTimeout(() => {
const randomNumber = Math.random();
if (randomNumber > 0.5) resolve('foo');
else abort('bar' /* abort reason here */);
}, 1000));
// 1 second later in console...
// => foo
// or
// => Promise aborted: bar
// it's a 50/50 chance, basically.
or you can just Abortable.Promise.abort(anyPromiseYouLike);
.
Copy-paste the code somewhere (let's say to a folder "abortable", for example). Import.
Simple function that gets JSON from server and returns an abortable promise now looks like this:
import Abortable from './abortable'
request(url: string, config: RequestInit, timeout?: number) {
return new Abortable.Promise((resolve, reject, abort) => {
Abortable.fetch(url, config).then(resp => resp.json().then(resolve).catch(reject)).catch(reject);
// Let's say we have our custom timeout:
if (timeout !== undefined)
setTimeout(() => abort('TimeOut'), timeout);
});
}
Following actions are NOT SAFE. Proceed at your own risk.
Just do this:
originalPromise = { ...window.Promise };
originalFetch = window.fetch;
window.Promise = Abortable.Promise;
window.fetch = Abortable.fetch;