Closed brandoncarl closed 9 years ago
Hey @brandoncarl. Yes, that's quite a lot of info :) no worries, though, all good stuff to discuss.
I'll say up front that my general philosophy right now is to try to keep when.js's API as lean as possible as we head toward 4.0, by providing the most essential building blocks, like then
, fold
, try
, lift
, etc., rather than attempt to provide all the utilities that can possibly be built from them. Devs all have their own approach to solving problems and use promises is a wide variety of ways, so trying to provide all possible utility methods is a slippery slope.
That said, I think there are ways to achieve the things you mention using existing APIs.
In your first example, it looks like the ultimate goal is to execute a binary function that looks like:
function computeResult(val1, val2) { ... }
With the additional constraint that val1
and val2
should be computed serially (and val2
should not be computed if the task computing val1
fails).
Here's a fairly simple way to do that, without using spread
.
var val1 = task1();
var val2 = val1.then(task2);
var result = when.try(computeResult, val1, val2);
In that case, if task1
fails, task2
will not execute. Similarly, computeResult
will not execute if either task1
or task2
fails. I think I got that right, but if it's not the same as what you're after, let me know where I goofed, and I'll try to get it right.
For the second and third example, there was actually a similar discussion over at cujojs/most very recently. It's pretty simple to write a reusable set
function:
// Write a simple (ie not promise-aware) set function
function set(k) {
return function(value, target) {
target[k] = value;
return target;
};
}
// Use it with promise.fold
// Incidentally, val1 can be a promise or a non-promise value in this case
var promiseForUpdatedObject = promiseForObject.fold(set("b"), val1);
And a reusable pick
function that will work with Arrays, Promises, reactive streams, and really anything that provides a "map-like" operation.
// Write a simple (ie not promise-aware) pick function
function pick(keys) {
return function(obj) {
// Array.map, or use lodash if you prefer
return keys.map(function(k) {
return x[k];
});
};
}
// Use it with promises:
var promise = when.resolve({ a : "hi", b : "there" })
promise.then(pick(["a", "b"])).spread(...);
// Or with an array
var arrayOfPairs = arrayOfObjects.map(pick(["a", "b"]));
// Or a reactive stream
var most = require('most');
var stream = most.create(...);
stream.map(pick(["a", "b"])).observe(console.log.bind(console));
Does that help?
@brandoncarl Ping. Any thoughts on the approaches above?
Hey Brian sorry for the delay. We went into production crunch. This is a great answer and I'll be back but closing for now. Thanks for the response!
On Friday, November 7, 2014 at 8:02 AM, Brian Cavalier wrote:
@brandoncarl (https://github.com/brandoncarl) Ping. Any thoughts on the approaches above?
— Reply to this email directly or view it on GitHub (https://github.com/cujojs/when/issues/385#issuecomment-62139002).
Cool, no problem. Hope all went well with the production release :)
Hi – I wanted to open a dialog about a few convenience functions to make promises more "functional". We can separate into separate issues if fitting. Not firm whatsoever on names, just wanted to start a dialog.
The first functions expand upon cases of
fold
and act as convenience functions for promise "chains". I would suggestprepend
,append
andset
.prepend
andappend
would be used for "passing" arrays through the chain. This would be as opposed to creating global scopes to pass variables across functions.Meanwhile,
set
would be used for assembling an object.Lastly, I am finding that the
spread
function is tempting me to write functions that return arrays (which I tend to find as a less desirable practice than return objects). Functions that return objects tend to be more flexible across use cases, as they don't determine the order of subsequent functions. I think that, taking a cue from Lodash/Underscore, apick
function could serve as a nice intermediary between functions that return objects, and "spread".For example:
Apologies for the long post – given that these are all somewhat "functional" in nature, I wanted to keep the initial dialog cohesive. If there are convenient ways of achieving these results, please do let me know!