-
Notifications
You must be signed in to change notification settings - Fork 35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Future #432
base: master
Are you sure you want to change the base?
Future #432
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,46 @@ | ||||||
'use strict'; | ||||||
|
||||||
class Future { | ||||||
constructor(executor) { | ||||||
this.executor = executor; | ||||||
} | ||||||
|
||||||
static of(value) { | ||||||
return new Future(resolve => resolve(value)); | ||||||
} | ||||||
|
||||||
static err(error) { | ||||||
return new Future((resolve, reject) => reject(error)); | ||||||
} | ||||||
|
||||||
chain(fn) { | ||||||
return new Future((resolve, reject) => | ||||||
this.run(value => fn(value).run(resolve, reject), error => reject(error)) | ||||||
); | ||||||
} | ||||||
|
||||||
map(fn) { | ||||||
return this.chain( | ||||||
value => | ||||||
tshemsedinov marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
new Future((resolve, reject) => { | ||||||
try { | ||||||
resolve(fn(value)); | ||||||
} catch (error) { | ||||||
reject(error); | ||||||
} | ||||||
}) | ||||||
); | ||||||
} | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could this perhaps be rewritten without double Future? map(fn) {
return new Future((resolve, reject) => {
this.run(value => {
try {
resolve(fn(value));
} catch (error) {
reject(error);
}
});
}); There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for bringing the attention here! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Implementation of |
||||||
|
||||||
run(successed, failed) { | ||||||
this.executor(successed, failed); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's important to catch errors the |
||||||
} | ||||||
|
||||||
promise() { | ||||||
return new Promise((resolve, reject) => { | ||||||
this.run(value => resolve(value), error => reject(error)); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the lambda is used for dropping other arguments |
||||||
}); | ||||||
} | ||||||
} | ||||||
|
||||||
module.exports = { Future }; |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,133 @@ | ||||||
'use strict'; | ||||||
|
||||||
const { Future, futurify } = require('..'); | ||||||
const metatests = require('metatests'); | ||||||
|
||||||
metatests.test('Future map/run', async test => { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
? (and in other tests) |
||||||
Future.of(3) | ||||||
.map(x => x ** 2) | ||||||
.run(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); | ||||||
}).run(value => { | ||||||
test.strictSame(value, 5); | ||||||
test.end(); | ||||||
}, test.mustNotCall()); | ||||||
}); | ||||||
|
||||||
metatests.test('Future reject', async test => { | ||||||
new Future((resolve, reject) => { | ||||||
reject(new Error('msg')); | ||||||
}).run(test.mustNotCall(), error => { | ||||||
test.strictSame(error.message, 'msg'); | ||||||
test.end(); | ||||||
}); | ||||||
}); | ||||||
|
||||||
metatests.test('Future error', async test => { | ||||||
Future.err(new Error('msg')).run(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'); | ||||||
}) | ||||||
.run(test.mustNotCall, error => { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
test.strictSame(error.message, 'msg'); | ||||||
test.end(); | ||||||
}); | ||||||
}); | ||||||
|
||||||
metatests.test('Future stateless', async test => { | ||||||
const f1 = Future.of(3); | ||||||
const f2 = f1.map(x => ++x); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
const f3 = f2.map(x => x ** 3); | ||||||
const f4 = f1.map(x => x * 2); | ||||||
|
||||||
f1.run(value => { | ||||||
test.strictSame(value, 3); | ||||||
}); | ||||||
|
||||||
f1.run(value => { | ||||||
test.strictSame(value, 3); | ||||||
}); | ||||||
|
||||||
f2.run(value => { | ||||||
test.strictSame(value, 4); | ||||||
}); | ||||||
|
||||||
f2.run(value => { | ||||||
test.strictSame(value, 4); | ||||||
}); | ||||||
|
||||||
f3.run(value => { | ||||||
test.strictSame(value, 64); | ||||||
}); | ||||||
|
||||||
f4.run(value => { | ||||||
test.strictSame(value, 6); | ||||||
}); | ||||||
|
||||||
test.end(); | ||||||
}); | ||||||
|
||||||
metatests.test('Future futurify success', async test => { | ||||||
const f1 = (a, b, callback) => { | ||||||
if (typeof a !== 'number' || typeof b !== 'number') { | ||||||
callback(new Error('Arguments must be numbers')); | ||||||
return; | ||||||
} | ||||||
callback(null, a + b); | ||||||
}; | ||||||
|
||||||
const f2 = futurify(f1); | ||||||
|
||||||
f2(10, 20).run(value => { | ||||||
test.strictSame(value, 30); | ||||||
test.end(); | ||||||
}); | ||||||
}); | ||||||
|
||||||
metatests.test('Future futurify fail', async test => { | ||||||
const f1 = (a, b, callback) => { | ||||||
if (typeof a !== 'number' || typeof b !== 'number') { | ||||||
callback(new Error('Arguments must be numbers')); | ||||||
return; | ||||||
} | ||||||
callback(null, a + b); | ||||||
}; | ||||||
|
||||||
const f2 = futurify(f1); | ||||||
|
||||||
f2('10', '20').run(test.mustNotCall, error => { | ||||||
test.strictSame(error.message, 'Arguments must be numbers'); | ||||||
test.end(); | ||||||
}); | ||||||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto