-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
Copy pathpromise-state.ts
68 lines (57 loc) · 2.12 KB
/
promise-state.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
import { tracked } from '@glimmer/tracking';
import type { Awaitable } from '@ember-data/request';
import { getPromiseResult, setPromiseResult } from '@ember-data/request';
const PromiseCache = new WeakMap<Awaitable, PromiseState>();
export class PromiseState<T = unknown, E = unknown> {
@tracked result: T | null = null;
@tracked error: E | null = null;
@tracked isPending = true;
@tracked isSuccess = false;
@tracked isError = false;
constructor(promise: Promise<T> | Awaitable<T, E>) {
const state = getPromiseResult<T, E>(promise);
if (state) {
if (state.isError) {
this.error = state.result;
this.isError = true;
this.isPending = false;
} else {
this.result = state.result;
this.isSuccess = true;
this.isPending = false;
}
} else {
void promise.then(
(result) => {
setPromiseResult(promise, { isError: false, result });
this.result = result;
this.isSuccess = true;
this.isPending = false;
},
(error: E) => {
setPromiseResult(promise, { isError: true, result: error });
this.error = error;
this.isError = true;
this.isPending = false;
}
);
}
}
}
const LegacyPromiseProxy = Symbol.for('LegacyPromiseProxy');
type LegacyAwaitable<T, E> = { promise: Promise<T> | Awaitable<T, E>; [LegacyPromiseProxy]: true };
function isLegacyAwaitable<T, E>(promise: object): promise is LegacyAwaitable<T, E> {
return LegacyPromiseProxy in promise && 'promise' in promise && promise[LegacyPromiseProxy] === true;
}
function getPromise<T, E>(promise: Promise<T> | Awaitable<T, E> | LegacyAwaitable<T, E>): Promise<T> | Awaitable<T, E> {
return isLegacyAwaitable(promise) ? promise.promise : promise;
}
export function getPromiseState<T = unknown, E = unknown>(promise: Promise<T> | Awaitable<T, E>): PromiseState<T, E> {
const _promise = getPromise(promise);
let state = PromiseCache.get(_promise) as PromiseState<T, E> | undefined;
if (!state) {
state = new PromiseState(_promise);
PromiseCache.set(_promise, state);
}
return state;
}