Skip to content

Commit

Permalink
Implement Future stateless and lazy Promise analogue
Browse files Browse the repository at this point in the history
Refs: #431
  • Loading branch information
tshemsedinov committed Jun 10, 2019
1 parent 43e59f4 commit 03802f9
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 0 deletions.
45 changes: 45 additions & 0 deletions lib/future.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
'use strict';

class Future {
constructor(executor) {
this.executor = executor;
}

static of(value) {
return new Future(resolve => resolve(value));
}

chain(fn) {
return new Future((resolve, reject) =>
this.fork(
value => fn(value).fork(resolve, reject),
error => reject(error)
)
);
}

map(fn) {
return this.chain(
value =>
new Future((resolve, reject) => {
try {
resolve(fn(value));
} catch (error) {
reject(error);
}
})
);
}

fork(successed, failed) {
this.executor(successed, failed);
}

promise() {
return new Promise((resolve, reject) => {
this.fork(value => resolve(value), error => reject(error));
});
}
}

module.exports = { Future };
1 change: 1 addition & 0 deletions metasync.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const submodules = [
'control', // Control flow utilities
'do', // Simple chain/do
'fp', // Async utils for functional programming
'future', // Future stateless and lazy Promise analogue
'memoize', // Async memoization
'poolify', // Create pool from factory
'queue', // Concurrent queue
Expand Down
92 changes: 92 additions & 0 deletions test/future.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
'use strict';

const { Future } = require('..');
const metatests = require('metatests');

metatests.test('Future map/fork', async test => {
Future.of(3)
.map(x => x ** 2)
.fork(value => {
test.strictSame(value, 9);
test.end();
});
});

metatests.test('Future lazy', async test => {
Future.of(3).map(test.mustNotCall());
test.end();
});

metatests.test('Future resolve', async test => {
new Future(resolve => {
setTimeout(() => {
resolve(5);
}, 0);
}).fork(value => {
test.strictSame(value, 5);
test.end();
}, test.mustNotCall());
});

metatests.test('Future reject', async test => {
new Future((resolve, reject) => {
reject(new Error('msg'));
}).fork(test.mustNotCall(), error => {
test.strictSame(error.message, 'msg');
test.end();
});
});

metatests.test('Future promise', async test => {
const value = await Future.of(6)
.map(x => ++x)
.map(x => x ** 3)
.promise();

test.strictSame(value, 343);
test.end();
});

metatests.test('Future catch', async test => {
Future.of(6)
.map(() => {
throw new Error('msg');
})
.fork(test.mustNotCall, error => {
test.strictSame(error.message, 'msg');
test.end();
});
});

metatests.test('Future stateless', async test => {
const f1 = Future.of(3);
const f2 = f1.map(x => ++x);
const f3 = f2.map(x => x ** 3);
const f4 = f1.map(x => x * 2);

f1.fork(value => {
test.strictSame(value, 3);
});

f1.fork(value => {
test.strictSame(value, 3);
});

f2.fork(value => {
test.strictSame(value, 4);
});

f2.fork(value => {
test.strictSame(value, 4);
});

f3.fork(value => {
test.strictSame(value, 64);
});

f4.fork(value => {
test.strictSame(value, 6);
});

test.end();
});

0 comments on commit 03802f9

Please sign in to comment.