-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfuture.js
122 lines (106 loc) · 2.41 KB
/
future.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
/*
* Provides facilities for resolution of work in the future
*/
/**
* A synchronization point for resolving a value at some point in the future through discontinuous flows. For example,
* an RPC request to a remote service.
*/
class Future {
constructor() {
this.resolved = false
this.promised = new Promise( (accept, reject) => {
if( this.resolved ){
if( this.accept ){
accept( this.value )
} else if( this.reject ){
reject( this.value )
} else {
throw new Error("Resolved but neither accepted or rejected.")
}
this.value = undefined
} else {
this.acceptPromise = accept
this.rejectPromise = reject
}
})
}
reject( value ){
if( this.resolved ){ throw new Error("Already resolved") }
this.resolved = true
if( this.rejectPromise ){
this.rejectPromise( value )
this._resolve()
} else {
this.reject = true
this.value = value
}
}
accept( value ){
if( this.resolved ){ throw new Error("Already resolved") }
this.resolved = true
if( this.acceptPromise ){
this.acceptPromise( value )
this._resolve()
} else {
this.accept = true
this.value = value
}
}
_resolve() {
this.acceptPromise = undefined
this.rejectPromise = undefined
}
}
function delay( forMilliseconds, value ) {
const future = new Future();
setTimeout( () => {
future.accept( value )
}, forMilliseconds );
return future.promised;
}
function promiseEvent( from, name ){
const future = new Future();
from.once(name, (event) => {
future.accept(event);
});
from.once('error', (why) => {
future.reject(why);
});
return future.promised;
}
async function parallel( promises ){
async function resolvePromise( p ){
try {
const value = await p;
return {ok: true, value};
}catch(problem){
return {ok:false, problem};
}
}
const resolutions = promises.map( ( p ) => {
return resolvePromise(p);
});
const results = await Promise.all( resolutions );
const out = results.reduce( ( output, result ) => {
if( result.ok ){
output.good.push(result.value);
} else {
output.bad.push(result.problem);
}
return output;
}, { good: [], bad: [] });
if( out.bad.length > 0 ){
//TODO: Figure out better way to dsiplay the multiple errors.
const error = new Error("Failed to resolves all promises");
error.good = out.good;
error.bad = out.bad;
throw error;
}
return out.good;
}
module.exports = {
Future,
delay,
promiseEvent,
parallel
};