-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathx-promise-set.js
121 lines (118 loc) · 3.08 KB
/
x-promise-set.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
'use strict'
const XIterable = require('x-iterable-base/template')
const {getPrototypeOf} = Object
const CALL_RESOLVE = (value, resolve) => resolve(value)
const CALL_REJECT = (value, resolve, reject) => reject(value)
const RETURN = x => x
const THROW = x => { throw x }
const RETURN_TRUE = () => true
function XPromiseSet (XPromise = Promise, XSet = Set) {
const mkpromise = promise => {
if (promise instanceof XPromise) {
return promise
}
if (typeof promise === 'function') {
return new XPromise(promise)
}
throw new TypeError('Cannot convert value to promise')
}
const mkmap = object => {
const origin = getPrototypeOf(object)
return {
has: x => origin.has(x),
delete: x => origin.delete(x),
entries: () => origin.entries(),
keys: () => origin.keys(),
values: () => origin.values(),
__proto__: object
}
}
const tryexec = fn => (value, resolve, reject) => {
try {
resolve(fn(value))
} catch (error) {
reject(error)
}
}
const mksum = (rsrj, rjrs, self) => new XPromise((...args) => {
const {[rsrj]: resolvereject, [rjrs]: rejectresolve} = args
const {size} = self
const rsrjresult = new XSet()
for (const promise of self) {
promise.then(
value => {
rsrjresult.add(value)
size === rsrjresult.size && resolvereject(rsrjresult)
},
rejectresolve
)
}
})
class PromiseSet extends XIterable(XSet) {
constructor (...args) {
super(args.map(mkpromise))
}
add (...args) {
args.map(mkpromise).forEach(promise => super.add(promise))
return this
}
delete (...args) {
args.forEach(promise => super.delete(promise))
return this
}
get all () {
return mksum(0, 1, this)
}
get race () {
return mksum(1, 0, this)
}
mapExecutor (onfulfill = CALL_RESOLVE, onreject = CALL_REJECT) {
return mkmap(
super.map(
promise => new Promise(
(resolve, reject) => promise.then(
value =>
onfulfill(value, resolve, reject),
reason =>
onreject(reason, resolve, reject)
)
)
)
)
}
map (onfulfill = RETURN, onreject = THROW) {
return this.mapExecutor(tryexec(onfulfill), tryexec(onreject))
}
filter (onfulfill = RETURN_TRUE, onreject = RETURN_TRUE) {
let {size} = this
const proto = super.map(
promise => new Promise(
(resolve, reject) => promise.then(
value => onfulfill(value) ? resolve(value) : --size,
error => onreject(error) ? reject(error) : --size
)
)
)
return mkmap({
get size () {
return size
},
__proto__: proto
})
}
forEach (onfulfill, onreject) {
this.map(onfulfill, onreject)
}
static get XPromiseSet () {
return XPromiseSet
}
static get XPromise () {
return XPromise
}
static get XSet () {
return XSet
}
}
return PromiseSet
}
module.exports = XPromiseSet