Skip to content

Commit 71c1a9b

Browse files
committed
Implement Future stateless and lazy Promise analogue
Refs: #431
1 parent 85509e9 commit 71c1a9b

File tree

3 files changed

+138
-0
lines changed

3 files changed

+138
-0
lines changed

lib/future.js

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
'use strict';
2+
3+
class Future {
4+
constructor(executor) {
5+
this.executor = executor;
6+
}
7+
8+
static of(value) {
9+
return new Future(resolve => resolve(value));
10+
}
11+
12+
chain(fn) {
13+
return new Future((resolve, reject) =>
14+
this.fork(
15+
value => fn(value).fork(resolve, reject),
16+
error => reject(error)
17+
)
18+
);
19+
}
20+
21+
map(fn) {
22+
return this.chain(
23+
value =>
24+
new Future((resolve, reject) => {
25+
try {
26+
resolve(fn(value));
27+
} catch (error) {
28+
reject(error);
29+
}
30+
})
31+
);
32+
}
33+
34+
fork(successed, failed) {
35+
this.executor(successed, failed);
36+
}
37+
38+
promise() {
39+
return new Promise((resolve, reject) => {
40+
this.fork(value => resolve(value), error => reject(error));
41+
});
42+
}
43+
}
44+
45+
module.exports = { Future };

metasync.js

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const submodules = [
1212
'control', // Control flow utilities
1313
'do', // Simple chain/do
1414
'fp', // Async utils for functional programming
15+
'future', // Future stateless and lazy Promise analogue
1516
'memoize', // Async memoization
1617
'poolify', // Create pool from factory
1718
'queue', // Concurrent queue

test/future.js

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
'use strict';
2+
3+
const { Future } = require('..');
4+
const metatests = require('metatests');
5+
6+
metatests.test('Future map/fork', async test => {
7+
Future.of(3)
8+
.map(x => x ** 2)
9+
.fork(value => {
10+
test.strictSame(value, 9);
11+
test.end();
12+
});
13+
});
14+
15+
metatests.test('Future lazy', async test => {
16+
Future.of(3).map(test.mustNotCall());
17+
test.end();
18+
});
19+
20+
metatests.test('Future resolve', async test => {
21+
new Future(resolve => {
22+
setTimeout(() => {
23+
resolve(5);
24+
}, 0);
25+
}).fork(value => {
26+
test.strictSame(value, 5);
27+
test.end();
28+
}, test.mustNotCall());
29+
});
30+
31+
metatests.test('Future reject', async test => {
32+
new Future((resolve, reject) => {
33+
reject(new Error('msg'));
34+
}).fork(test.mustNotCall(), error => {
35+
test.strictSame(error.message, 'msg');
36+
test.end();
37+
});
38+
});
39+
40+
metatests.test('Future promise', async test => {
41+
const value = await Future.of(6)
42+
.map(x => ++x)
43+
.map(x => x ** 3)
44+
.promise();
45+
46+
test.strictSame(value, 343);
47+
test.end();
48+
});
49+
50+
metatests.test('Future catch', async test => {
51+
Future.of(6)
52+
.map(() => {
53+
throw new Error('msg');
54+
})
55+
.fork(test.mustNotCall, error => {
56+
test.strictSame(error.message, 'msg');
57+
test.end();
58+
});
59+
});
60+
61+
metatests.test('Future stateless', async test => {
62+
const f1 = Future.of(3);
63+
const f2 = f1.map(x => ++x);
64+
const f3 = f2.map(x => x ** 3);
65+
const f4 = f1.map(x => x * 2);
66+
67+
f1.fork(value => {
68+
test.strictSame(value, 3);
69+
});
70+
71+
f1.fork(value => {
72+
test.strictSame(value, 3);
73+
});
74+
75+
f2.fork(value => {
76+
test.strictSame(value, 4);
77+
});
78+
79+
f2.fork(value => {
80+
test.strictSame(value, 4);
81+
});
82+
83+
f3.fork(value => {
84+
test.strictSame(value, 64);
85+
});
86+
87+
f4.fork(value => {
88+
test.strictSame(value, 6);
89+
});
90+
91+
test.end();
92+
});

0 commit comments

Comments
 (0)