@nextgis/cancelable-promise
Version:
306 lines (301 loc) • 8.91 kB
JavaScript
/** Bundle of @nextgis/cancelable-promise; version: 3.0.0; author: NextGIS */
var __defProp$3 = Object.defineProperty;
var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField$3 = (obj, key, value) => __defNormalProp$3(obj, key + "" , value);
class CancelError extends Error {
constructor() {
super();
__publicField$3(this, "name", "CancelError");
Object.setPrototypeOf(this, CancelError.prototype);
}
}
var __defProp$2 = Object.defineProperty;
var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField$2 = (obj, key, value) => __defNormalProp$2(obj, key + "" , value);
class PromiseControl {
constructor(options = {}) {
this.options = options;
__publicField$2(this, "_promises", /* @__PURE__ */ new Map());
}
get isLoaded() {
return this._promises.size > 0;
}
remove(promise) {
if (this._promises.has(promise)) {
this._promises.delete(promise);
this._onStop();
}
}
get(promise) {
return this._promises.get(promise);
}
add(promise, name) {
const key = name ? name : promise;
const exist = this._promises.get(key);
if (this.options.onStart && !this.isLoaded) {
this.options.onStart();
}
if (exist) {
return exist;
}
this._promises.set(key, promise);
promise.finally(() => {
this.remove(key);
});
return promise;
}
abort() {
if (this.isLoaded) {
this._promises.forEach((x) => {
if (x.cancel) {
x.cancel();
}
});
this._promises.clear();
this._onStop();
}
}
waitFunc(func, name = "") {
name = name || func.name;
const exist = this.get(name);
if (exist) {
return exist;
}
return this.add(func(), name);
}
WaitForMe(name = "") {
const get = this.get.bind(this);
const add = this.add.bind(this);
return function(target, key, descriptor) {
const originalMethod = descriptor.value;
name = name || key;
descriptor.value = function(...args) {
const exist = get(name);
if (exist) {
return exist;
}
const result = add(originalMethod.apply(this, args), name);
return result;
};
return descriptor;
};
}
/** @deprecated use {@link PromiseControl.WaitForMe } instead */
GetOrCreateDecorator(name = "") {
return this.WaitForMe(name);
}
_onStop() {
if (this.options.onStop && !this.isLoaded) {
this.options.onStop();
}
}
}
var __defProp$1 = Object.defineProperty;
var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField$1 = (obj, key, value) => __defNormalProp$1(obj, key + "" , value);
class TimeoutError extends Error {
constructor() {
super();
__publicField$1(this, "name", "TimeoutError");
Object.setPrototypeOf(this, TimeoutError.prototype);
}
}
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
var _a;
const handleCallback = (resolve, reject, callback, r) => {
try {
resolve(callback(r));
} catch (e) {
reject(e);
}
};
let ID = 0;
_a = Symbol.toStringTag;
const _CancelablePromise = class _CancelablePromise {
constructor(executor, timeout) {
// @ts-expect-error Property '[Symbol.toStringTag]' has no initializer and is not definitely assigned in the constructor
__publicField(this, _a);
__publicField(this, "id", ID++);
__publicField(this, "_isCanceled", false);
__publicField(this, "_isPending", true);
__publicField(this, "_promise");
__publicField(this, "_cancelPromise");
__publicField(this, "_cancelHandlers", []);
__publicField(this, "_setCanceledCallback");
__publicField(this, "_parentPromise");
__publicField(this, "_children", []);
this._cancelPromise = new Promise((resolve_, reject_) => {
this._setCanceledCallback = (er) => resolve_(er || new CancelError());
});
const promises = [
this._cancelPromise,
new Promise((resolve, reject) => {
const onResolve = (value) => {
if (value instanceof _CancelablePromise) {
this.attach(value);
} else {
this._isPending = false;
}
resolve(value);
};
const onReject = (error) => {
this._isPending = false;
reject(error);
};
const onCancel = (handler) => {
if (!this._isPending) {
throw new Error(
"The `onCancel` handler was attached after the promise settled."
);
}
this._cancelHandlers.push(handler);
};
return executor(onResolve, onReject, onCancel);
})
];
if (timeout) {
promises.push(
new Promise((resolve, reject) => {
setTimeout(() => {
if (this._isPending) {
try {
this.cancel();
} finally {
reject(new TimeoutError());
}
}
}, timeout);
})
);
}
this._promise = Promise.race(promises);
}
static createControl(opt) {
return new PromiseControl(opt);
}
static resolve(value) {
return new _CancelablePromise((resolve) => resolve(value));
}
static reject(value) {
return new _CancelablePromise((resolve, reject) => reject(value));
}
static all(values) {
return new _CancelablePromise((resolve, reject) => {
Promise.all(values).then(resolve).catch(reject);
}).catch((er) => {
if (er instanceof this.CancelError) {
for (const v of values) {
const v_ = v;
if ("cancel" in v_) {
v_.cancel();
}
}
}
throw er;
});
}
attach(p) {
if (this._isCanceled) {
p.cancel();
} else {
this._children.push(p);
}
}
then(onfulfilled, onrejected) {
const p = new _CancelablePromise((resolve, reject) => {
if (this._promise) {
const reject_ = (r) => {
if (onrejected) {
handleCallback(resolve, reject, onrejected, r);
} else {
reject(r);
}
};
this._promise.then((r) => {
if (this._isCanceled) {
reject_(r);
} else {
if (onfulfilled) {
handleCallback(resolve, reject, onfulfilled, r);
} else {
resolve(r);
}
}
}, reject_);
}
});
p._parentPromise = this;
this._children.push(p);
return p;
}
catch(onrejected) {
if (this._isCanceled && onrejected) {
onrejected(new CancelError());
}
return this.then(void 0, onrejected);
}
finally(onfinally) {
if (this._promise) {
return this._promise.finally(onfinally);
}
if (this._isCanceled) {
return Promise.reject(new CancelError());
}
return Promise.reject(onfinally);
}
cancel() {
if (this._isCanceled || !this._isPending) {
return this;
}
this._isCanceled = true;
const parent = this._getTopParent();
if (parent) {
parent.cancel();
}
if (this._children) {
this._children.forEach((x) => x.cancel());
}
if (this._isPending) {
if (this._cancelHandlers.length) {
try {
for (const handler of this._cancelHandlers) {
handler();
}
} catch (e) {
}
}
if (this._setCanceledCallback) {
this._setCanceledCallback();
}
}
this._destroy();
return this;
}
_getTopParent() {
let parent = this._parentPromise;
let hasParent = !!parent;
while (hasParent) {
if (parent && parent._parentPromise) {
parent = parent._parentPromise;
hasParent = !!parent;
} else {
hasParent = false;
}
}
return parent;
}
_destroy() {
this._setCanceledCallback = void 0;
this._cancelPromise = void 0;
this._promise = void 0;
}
};
__publicField(_CancelablePromise, "CancelError", CancelError);
__publicField(_CancelablePromise, "TimeoutError", TimeoutError);
__publicField(_CancelablePromise, "PromiseControl", PromiseControl);
let CancelablePromise = _CancelablePromise;
Object.setPrototypeOf(CancelablePromise.prototype, Promise.prototype);
export { CancelablePromise as default };
//# sourceMappingURL=cancelable-promise.esm-browser.js.map