-
Notifications
You must be signed in to change notification settings - Fork 113
/
CancelablePromise.ts
201 lines (177 loc) · 4.28 KB
/
CancelablePromise.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
/**
* Cancelable promises extend base promises and provide a cancel functionality than can be used to cancel the execution or task of the promise.
*
* These type of promises can be used to prevent additional processing when the data is not longer required (e.g. HTTP request for data that is not longer necessary)
*/
export class CancelablePromise<T>
{
public onResolve: (value: any)=> void;
public onReject: (error: any)=> void;
public onCancel: ()=> void;
/**
* Flag to indicate if the promise has been fulfilled.
*
* Promise has ben fulfilled when value/error is set.
*/
public fulfilled: boolean = false;
/**
* Flag to indicate if the promise was rejected.
*
* Only set when the promise is fulfilled.
*/
public rejected: boolean = false;
/**
* Flag set true when the resolve or reject method are called.
*/
public called: boolean = false;
/**
* Output value of the promise.
*
* Set with the output value if promise was fulfilled and not rejected.
*
* Stores the error value if the promise was rejected.
*/
public value: T;
public constructor(executor: (resolve: (value: T | PromiseLike<T>)=> void, reject: (reason?: any)=> void)=> void)
{
const resolve = (v): void =>
{
this.fulfilled = true;
this.value = v;
if (typeof this.onResolve === 'function')
{
this.onResolve(this.value);
this.called = true;
}
};
const reject = (reason): void =>
{
this.rejected = true;
this.value = reason;
if (typeof this.onReject === 'function')
{
this.onReject(this.value);
this.called = true;
}
};
try
{
executor(resolve, reject);
}
catch (error)
{
reject(error);
}
}
/**
* Request to cancel the promise execution.
*
* @returns True if the promise is canceled successfully, false otherwise.
*/
public cancel(): boolean
{
// TODO <ADD CODE HERE>
return false;
}
/**
* Executed after the promise is fulfilled.
*
* @param callback - Callback to receive the value.
* @returns Promise for chainning.
*/
public then(callback: (value: any)=> void): CancelablePromise<T>
{
this.onResolve = callback;
if (this.fulfilled && !this.called)
{
this.called = true;
this.onResolve(this.value);
}
return this;
}
/**
* Catch any error that occurs in the promise.
*
* @param callback - Method to catch errors.
* @returns Promise for chainning.
*/
public catch(callback: (error: any)=> void): CancelablePromise<T>
{
this.onReject = callback;
if (this.rejected && !this.called)
{
this.called = true;
this.onReject(this.value);
}
return this;
}
/**
* Finally callback
*
* @param callback - Method to be called.
* @returns Promise for chainning.
*/
public finally(callback: Function): CancelablePromise<T>
{
// TODO <ADD CODE HERE>
return this;
}
/**
* Create a resolved promise.
*
* @param val - Value to pass.
* @returns Promise created with resolve value.
*/
public static resolve<T>(val: T): CancelablePromise<T>
{
return new CancelablePromise<T>(function executor(resolve, _reject)
{
resolve(val);
});
}
/**
* Create a rejected promise.
*
* @param reason - Reason to reject the promise.
* @returns Promise created with rejection reason.
*/
public static reject(reason: any): CancelablePromise<any>
{
return new CancelablePromise(function executor(resolve, reject)
{
reject(reason);
});
}
/**
* Wait for a set of promises to finish, creates a promise that waits for all running promises.
*
* If any of the promises fail it will reject altough some of them may have been completed with success.
*
* @param promises - List of promisses to syncronize.
* @returns Promise that will resolve when all of the running promises are fullfilled.
*/
public static all(promises: CancelablePromise<any>[]): CancelablePromise<any>
{
const fulfilledPromises = [];
const result = [];
function executor(resolve, reject): void
{
promises.forEach((promise, index) =>
{
return promise
.then((val) =>
{
fulfilledPromises.push(true);
result[index] = val;
if (fulfilledPromises.length === promises.length)
{
return resolve(result);
}
})
.catch((error) => {return reject(error);});
}
);
}
return new CancelablePromise(executor);
}
}