Comparison of two different approaches to structuring code that uses Promises.
Version using .then(), from Complex task dependencies:
files.getLastTwoVersions(filename)
.then(function(items) {
return [versions.get(items.last),
versions.get(items.previous)];
})
.spread(function(v1, v2) {
return diffService.compare(v1.blob, v2.blob)
})
.then(function(diff) {
// voila, diff is ready. Do something with it.
});With wrapped functions
items = files.getLastTwoVersions(Promise.resolve(filename));
v1 = versions.get(items.get("last"));
v2 = versions.get(items.get("previous"));
diff = diffService.compare(v1.get("blob"), v2.get("blob"));
diff.then(function (s) {
// voila, diff is ready. Do something with it
});3rd Alternative (full source)
function property(name) {
return function(obj) { return obj[name]; }
}
items = files.getLastTwoVersions(filename);
v1 = files.then(property('first')).then(versions.get);
v2 = files.then(property('last')).then(versions.get);
diff = Promise.join(v1.then(property('blob')), v2.then(property('blob')))
.spread(diffService.compare);
diff.then(function(s) { /* voila */ });In general, you want the inputs of your function to always be values and let then and spread do the promise unpacking. Its almost equally easy to write diffService.compare(v1.get("blob"), v2.get("blob")); and Promise.join(v1.then(property('blob')), v2.then(property('blob'))).spread(diffService.compare);, except the second one is more general.
Instead of writing separate functions that work with promises, write higher order functions that can be passed to then and spread. Note that these (such as the property function) do not unpack promises. Separation of concerns :)
With ES6 arrow functions defining higher order functions becomes quite elegant:
let property = name => obj => obj[name];
items = files.getLastTwoVersions(filename);
v1 = files.then(property('first')).then(versions.get);
v2 = files.then(property('last')).then(versions.get);
diff = Promise.join(v1.then(property('blob')), v2.then(property('blob')))
.spread(diffService.compare);
diff.then(s => /* voila */);And perhaps quite unnecessary :)
items = files.getLastTwoVersions(filename);
v1 = files.then(items => versions.get(items.first));
v2 = files.then(items => versions.get(items.last));
diff = Promise.join(v1, v2).spread((v1, v2) =>
diffService.compare(v1.blob, v2.blob));
diff.then(s => /* voila */);
But you will have to wrap all language built-ins. That gets tedious real fast, not to mention that the performance suffers too, and at that point I'd rather use ClojureScript :)
Arrow functions likely make the entire thing super-short.