-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.ts
71 lines (59 loc) · 2.24 KB
/
index.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
// cancelable-promise/index.ts
//
// Cancelable promises.
//
// Usage:
// ```
// import {CancelablePromise} from '@rtm/cancelable-promise';
//
// Construct a new promise:
// new CancelablePromise((resolve, reject[, cancel]) => {...})
//
// Cancel a promise via a canceler:
// new CancelablePromise((resolve, reject) => {...}, canceler])
//
// Be alerted when a promise is canceled:
// cancelablePromise.onCancel(...).then(...)
// ```
type CancelableExecutor<T> = (
resolve: (value?: T | PromiseLike<T>) => void,
reject: (reason?: any) => void,
cancel: (reason?: any) => void
) => void;
enum State { PENDING, FULFILLED, REJECTED, CANCELED};
export class CancelablePromise<T> extends Promise<T> {
// Static method to create a canceled promise, used for what?
static cancel(detail) { return new this((resolve, reject, cancel) => cancel(detail)); }
private state: State = State.PENDING;
private cancelDetail: any;
private onCancels: Function[] = [];
constructor(executor: CancelableExecutor<T>, canceler?: Promise<any>) {
super((resolve, reject) => {
if (canceler) canceler.then(detail => this.cancel(detail));
// Wait a tick, then maybe call the executor.
Promise.resolve().then(() => {
if (this.state === State.CANCELED) return;
executor(
value => { if (this.state === State.PENDING) { this.state = State.FULFILLED; resolve(value); } },
reason => { if (this.state === State.PENDING) { this.state = State.REJECTED; reject(reason); } },
detail => { this.cancel(detail); });
});
});
}
// Callback for cancellation.
public onCancel(handler: Function): CancelablePromise<T> {
if (this.state === State.CANCELED) handler(this.cancelDetail);
else this.onCancels.push(handler);
return this;
}
// Convenience property for a promise which fulfills on cancellation.
public get canceled() { return new Promise(resolved => this.onCancel(resolved)); }
// Internal routine to handle canceling either via `canceler` or call to `cancel` parameter to executor.
private cancel(detail) {
if (this.state === State.PENDING) {
this.cancelDetail = detail;
this.state = State.CANCELED;
this.onCancels.forEach(handler => handler(this.cancelDetail));
}
};
}