-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Thoughts on Q.async #77
Comments
I don't think this makes much sense, simply because we have no idea which of the arguments should be resolved in parallel versus not. I.e. should that be let sumOfStuff = Q.async(function* (a, b, c) {
let [A, B, C] = [yield a, yield b, yield c];
// ...
}); or let sumOfStuff = Q.async(function* (a, b, c) {
let [A, B, C] = yield Q.all([a, b, c]);
// ...
}); or let sumOfStuff = Q.async(function* (a, b, c) {
let [A, B] = yield Q.all([a, b]);
let C = yield c;
// ...
}); or even let sumOfStuff = Q.async(function* (a, b, c) {
let [A, B, C] = yield Q.allResolved([a, b, c]);
// error recovery code for rejected A, B, or C
// ...
}); |
For a well behaved promise, does it actually make a difference whether they're resolved in serial or parallel? I would envisage error handling code for arguments having to sit outside the function: let sumOfStuff = Q.async(function* (a, b, c) {
// ...
}).fail(function(err){
//error recovery for rejected parameters
}); but error recovery is a good argument for doing it the manual way, I hadn't thought of that. |
You are right, sorry. I was confusing this with the case of calling multiple promise-returning functions. It still seems likely that there are significant differences, since each In that case it sounds like the convenience method you're asking for could be implemented as Q.deepAsync = function (generator) {
return Q.async(function *() {
var args = Array.prototype.slice.call(arguments);
var argsResolved = yield Q.all(args);
return generator.apply(this, argsResolved);
});
}; (off the top of my head, untested, might be buggy, etc. disclaimer) |
@Gozala has previously recommended (privately) that we add That probably does not diminish the utility of a wrapper for synchronizing arguments. I will entertain the introduction of |
Let’s close this issue and open a new issue for an orthogonal |
To be more precise we use minimalistic Q subset with addition of Idea behind is just to ease expression of computation on promise values. So instead of having utilities like I have no idea how that would work with remote promises, but I guess in exact same way as |
@kriskowal re: remote objects and This doesn't really address your concern, but perhaps indicates that |
@domenic meta-promise was experiment that should be pretty easy to update to make it compatible with all JS engines supporting Proxies. Although from that experience I learned that making promises too much like regular objects was very confusing. I think syntax in the ES proposals http://wiki.ecmascript.org/doku.php?id=strawman:concurrency is probably a best way to go about it: files!filter(function (name) {
return (name.slice(-3) === '.js');
}); Makes it obvious for reader that operation happens eventually rather then now. I also have experimented with that approach in clojurescript where you have much more control of a language |
@Gozala Without new syntax, what about something like |
I guess that may work, but don't know if it's distinct enough for users to spot though. Still I think promised(filter)(function(name) {
return (name.slice(-3) === '.js');
}, files) |
@domenic BTW if you have access to generators than you can use |
Just recalled that @dherman has a well maintained library http://taskjs.org/ that implements very similar idea |
@Gozala Haha yes |
@domenic Oh BTW as of https://gist.github.com/1372013 I think most of the things you do there are better of in the streams land, in my opinion plain promises are not well suited for representing sequential values. Although you can build streams using promises which I tried https://github.com/Gozala/streamer/wiki/stream |
The way remote promises should work (they are presently broken in Q-Comm) is that the promise will be locally resolved in ½ RTT from the remote resolution. The local resolution will have the promise API for passing messages to the remote promise. Like this: var remote = getRemotePromise();
remote.get('a') // works here, and will resolve in ½ RTT of remote resolution
remote.then(function (remote) {
remote.get('a') // will resolve in 1 + ½ full RTT after remote resolution
// a minimum of 2 round trips from the previous event
}) As you can see, "when" will always introduce latency by waiting for synchronization. The only reason to wait for a remote promise is to way for synchronization side-effects, which should be relatively rare for performance reasons. |
In fact we don't implement |
I like the idea of having a separate Q.promised function, it should be simple enough to wrap var function = Q.promised(Q.async(function* (arg1, arg2){
})); So I think that's a good solution. Remote objects are a very different scenario. My initial thought would be to stick to the current get, invoke etc. but let people easily extend that by adding their own functions which just call into those base functions. If you're looking at processing lists, I think it's well worth considering libraries like Reactive Extensions. Lists are very different to promises, and if we want to do work on remote lists and apply things like remote filter functions, we should consider a separate library (and learn from things like LINQ to SQL). I do think many of these libraries may benefit from an 'all' method, which returns a promise for the complete list/stream returned as an array. Just my 2 cents worth. |
Closing in favor of #87 |
This is just a thought, feel free to disagree with me, but I'd just like to throw the idea out there.
I have a suspicion, that once yield is available in more environments (I'm currently writing a shim to compile it to ECMA5 based on the current standards) we'll see lots of methods that look like the following.
That is to say, lots of functions will begin by yielding on all their arguments, either one at a time, or using something like Q.all.
What might be preferable, would be to resolve all promises that are passed as arguments, before giving them to the function. The only down side, is that it prevents you from writing functions like:
Perhaps we could have some way of annotating the function as
lazy
but resolve all arguments by default?The text was updated successfully, but these errors were encountered: