-
Notifications
You must be signed in to change notification settings - Fork 141
/
PromiseState.js
132 lines (116 loc) · 4.34 KB
/
PromiseState.js
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
export default class PromiseState {
// creates a new PromiseState that is pending
static create(meta) {
return new PromiseState({
pending: true,
meta: meta
})
}
// creates as PromiseState that is refreshing
// can be called without a previous PromiseState and will be both pending and refreshing
static refresh(previous, meta) {
const p = previous || PromiseState.create(meta)
return new PromiseState({
pending: p.pending,
refreshing: true,
fulfilled: p.fulfilled,
rejected: p.rejected,
value: p.value,
reason: p.reason,
meta: p.meta
})
}
// creates a PromiseState that is resolved with the given value.
// if the given value is already a PromiseState,
// it will be returned as is and ignore the provided meta.
static resolve(value, meta) {
if (value instanceof PromiseState) {
return value
}
return new PromiseState({
fulfilled: true,
value: value,
meta: meta
})
}
// creates a PromiseState that is rejected with the given reason
static reject(reason, meta) {
return new PromiseState({
rejected: true,
reason: reason,
meta: meta
})
}
// The PromiseState.all(iterable) method returns a PromiseState
// that resolves when all of the PromiseStates in the iterable
// argument have resolved, or rejects with the reason of the
// first passed PromiseState that rejects.
static all(iterable) {
if (!Array.isArray(iterable)) {
iterable = Array.from(iterable)
}
return new PromiseState({
pending: iterable.some(ps => ps.pending),
refreshing: iterable.some(ps => ps.refreshing),
fulfilled: iterable.every(ps => ps.fulfilled),
rejected: iterable.some(ps => ps.rejected),
value: iterable.map(ps => ps.value),
reason: (iterable.find(ps => ps.reason) || {}).reason,
meta: iterable.map(ps => ps.meta)
})
}
// The PromiseState.race(iterable) method returns a PromiseState
// that resolves or rejects as soon as one of the PromiseStates in
// the iterable resolves or rejects, with the value or reason
// from that PromiseState.
static race(iterable) {
if (!Array.isArray(iterable)) {
iterable = Array.from(iterable)
}
const winner = iterable.find(ps => ps.settled)
return new PromiseState({
pending: !winner && iterable.some(ps => ps.pending),
refreshing: !winner && iterable.some(ps => ps.refreshing),
fulfilled: winner && winner.fulfilled,
rejected: winner && winner.rejected,
value: winner && winner.value,
reason: winner && winner.reason,
meta: winner && winner.meta
})
}
// Constructor for creating a raw PromiseState. DO NOT USE DIRECTLY. Instead, use PromiseState.create() or other static constructors
constructor({ pending = false, refreshing = false, fulfilled = false, rejected = false, value = null, reason = null, meta = {} }) {
this.pending = pending
this.refreshing = refreshing
this.fulfilled = fulfilled
this.rejected = rejected
this.settled = fulfilled || rejected
this.value = value
this.reason = reason
this.meta = meta
}
// Appends and calls fulfillment and rejection handlers on the PromiseState,
// and returns a new PromiseState resolving to the return value of the called handler,
// or to its original settled value if the promise was not handled.
// The handler functions take the value/reason and meta as parameters.
// (i.e. if the relevant handler onFulfilled or onRejected is undefined).
// Note, unlike Promise.then(), these handlers are called immediately.
then(onFulFilled, onRejected) {
if (this.fulfilled && onFulFilled) {
return PromiseState.resolve(onFulFilled(this.value, this.meta), this.meta)
}
if (this.rejected && onRejected) {
return PromiseState.resolve(onRejected(this.reason, this.meta), this.meta)
}
return this
}
// Appends and calls a rejection handler callback to the PromiseState,
// and returns a new PromiseState resolving to the return value of the
// callback if it is called, or to its original fulfillment value if
// the PromiseState is instead fulfilled. The handler function take
// the reason and meta as parameters. Note, unlike Promise.catch(),
// this handlers is called immediately.
catch(onRejected) {
return this.then(undefined, onRejected)
}
}