blob: 406367dfe07623d2085900e8a2004edc2b8617b2 [file] [log] [blame]
Leo Repp58b9f112021-11-22 11:57:47 +01001'use strict';
2
3class CancelError extends Error {
4 constructor() {
5 super('Promise was canceled');
6 this.name = 'CancelError';
7 }
8}
9
10class 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
74Object.setPrototypeOf(PCancelable.prototype, Promise.prototype);
75
76module.exports = PCancelable;
77module.exports.CancelError = CancelError;