/**
* Abortable Promise
*
* @author dondevi
* @create 2019-05-27
*/
import getAbortController from "./controller.js";
export default class AbortablePromise extends Promise {
constructor (executor, abortController = getAbortController()) {
super((resolve, reject) => {
executor(resolve, reject, abortController.signal);
});
this.abortController = abortController;
}
then (onFulfilled, onRejected) {
return new AbortablePromise((resolve, reject, signal) => {
const onSettled = (status, value, callback) => {
if ("function" === typeof callback) {
value = callback(value);
if (value instanceof AbortablePromise) {
Object.assign(signal, value.abortController.signal);
}
return resolve(value);
}
"resolved" === status && resolve(value);
"rejected" === status && reject(value);
}
super.then(
value => onSettled("resolved", value, onFulfilled),
reason => onSettled("rejected", reason, onRejected)
);
}, this.abortController);
}
// Equivalent to this.then(undefined, onRejected)
// catch (onRejected) {}
abort (reason) {
return new AbortablePromise((resolve, reject) => {
Promise.resolve().then(() => {
this.abortController.abort(reason);
this.then(resolve, reject);
});
}, this.abortController);
}
static all (promises) {
return new AbortablePromise((resolve, reject, signal) => {
setPromisesAbort(promises, signal);
Promise.all(promises).then(resolve, reject);
});
}
static race (promises) {
return new AbortablePromise((resolve, reject, signal) => {
setPromisesAbort(promises, signal);
Promise.race(promises).then(resolve, reject);
});
}
};
/**
* Set promises abort
* @param {Array} promises - list of promise
* @param {Object} signal - abort signal
*/
function setPromisesAbort (promises, signal) {
signal.onabort = reason => {
promises.forEach((promise) => {
if (promise instanceof AbortablePromise) {
promise.abort(reason).catch(error => error);
}
});
}
}