| Leo Repp | 58b9f11 | 2021-11-22 11:57:47 +0100 | [diff] [blame^] | 1 | 'use strict'; |
| 2 | |
| 3 | class CancelError extends Error { |
| 4 | constructor() { |
| 5 | super('Promise was canceled'); |
| 6 | this.name = 'CancelError'; |
| 7 | } |
| 8 | } |
| 9 | |
| 10 | class PCancelable { |
| 11 | static fn(fn) { |
| 12 | return function () { |
| 13 | const args = [].slice.apply(arguments); |
| 14 | return new PCancelable((onCancel, resolve, reject) => { |
| 15 | args.unshift(onCancel); |
| 16 | fn.apply(null, args).then(resolve, reject); |
| 17 | }); |
| 18 | }; |
| 19 | } |
| 20 | |
| 21 | constructor(executor) { |
| 22 | this._pending = true; |
| 23 | this._canceled = false; |
| 24 | |
| 25 | this._promise = new Promise((resolve, reject) => { |
| 26 | this._reject = reject; |
| 27 | |
| 28 | return executor( |
| 29 | fn => { |
| 30 | this._cancel = fn; |
| 31 | }, |
| 32 | val => { |
| 33 | this._pending = false; |
| 34 | resolve(val); |
| 35 | }, |
| 36 | err => { |
| 37 | this._pending = false; |
| 38 | reject(err); |
| 39 | } |
| 40 | ); |
| 41 | }); |
| 42 | } |
| 43 | |
| 44 | then() { |
| 45 | return this._promise.then.apply(this._promise, arguments); |
| 46 | } |
| 47 | |
| 48 | catch() { |
| 49 | return this._promise.catch.apply(this._promise, arguments); |
| 50 | } |
| 51 | |
| 52 | cancel() { |
| 53 | if (!this._pending || this._canceled) { |
| 54 | return; |
| 55 | } |
| 56 | |
| 57 | if (typeof this._cancel === 'function') { |
| 58 | try { |
| 59 | this._cancel(); |
| 60 | } catch (err) { |
| 61 | this._reject(err); |
| 62 | } |
| 63 | } |
| 64 | |
| 65 | this._canceled = true; |
| 66 | this._reject(new CancelError()); |
| 67 | } |
| 68 | |
| 69 | get canceled() { |
| 70 | return this._canceled; |
| 71 | } |
| 72 | } |
| 73 | |
| 74 | Object.setPrototypeOf(PCancelable.prototype, Promise.prototype); |
| 75 | |
| 76 | module.exports = PCancelable; |
| 77 | module.exports.CancelError = CancelError; |