'use strict'; class CancelError extends Error { constructor() { super('Promise was canceled'); this.name = 'CancelError'; } get isCanceled() { return true; } } class PCancelable { static fn(userFn) { return function () { const args = [].slice.apply(arguments); return new PCancelable((resolve, reject, onCancel) => { args.push(onCancel); userFn.apply(null, args).then(resolve, reject); }); }; } constructor(executor) { this._cancelHandlers = []; this._isPending = true; this._isCanceled = false; this._promise = new Promise((resolve, reject) => { this._reject = reject; return executor( value => { this._isPending = false; resolve(value); }, error => { this._isPending = false; reject(error); }, handler => { this._cancelHandlers.push(handler); } ); }); } then(onFulfilled, onRejected) { return this._promise.then(onFulfilled, onRejected); } catch(onRejected) { return this._promise.catch(onRejected); } finally(onFinally) { return this._promise.finally(onFinally); } cancel() { if (!this._isPending || this._isCanceled) { return; } if (this._cancelHandlers.length > 0) { try { for (const handler of this._cancelHandlers) { handler(); } } catch (err) { this._reject(err); } } this._isCanceled = true; this._reject(new CancelError()); } get isCanceled() { return this._isCanceled; } } Object.setPrototypeOf(PCancelable.prototype, Promise.prototype); module.exports = PCancelable; module.exports.CancelError = CancelError;