Skip to content

Instantly share code, notes, and snippets.

@JamesMGreene
Created November 24, 2012 15:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JamesMGreene/4140215 to your computer and use it in GitHub Desktop.
Save JamesMGreene/4140215 to your computer and use it in GitHub Desktop.
Using Q, is this the best way to pass the results of two sequenced promises to the subsequent `then`/`spread` clause?
'use strict';
var Q = require('q');
var cmd = new require('commander').Command();
var client = new require('myAwesomeApi').Client();
var getUsername = function(done) {
var username;
cmd.prompt('Username: ', function(name) {
if (!name) {
done(new Error('You must provide a username!'));
}
else {
done(null, username);
}
});
};
var getPassword = function(done) {
cmd.password('Password: ', '*', function(pass) {
if (!pass) {
done(new Error('You must provide a password!'));
}
else {
process.stdin.destroy();
done(null, pass);
}
});
};
Q.napply(getUsername, null, []).then(function(username) {
return Q.napply(getPassword, null, []).then(function(password) {
return Q.resolve([username, password]);
});
}).spread(function(username, password) {
return Q.napply(client.login, client, [username, password]);
})
@domenic
Copy link

domenic commented Nov 26, 2012

API reference is pretty outdated :-/. end is deprecated; done is a superset of its functionality (roughly, .then(f, r, p).end() <-> .done(f, r, p)).

Also we just deprecated Q.nbind in 0.8.11 so those lines above become

var getUsernameP = Q.nfbind(getUsername);
var getPasswordP = Q.nfbind(getPassword);
var loginP = Q.nfbind(client.login.bind(client));

@domenic
Copy link

domenic commented Nov 26, 2012

See here for a full list of deprecations and alternatives.

@kriskowal
Copy link

@JamesMGreene I think @domenic covered it all, except of course that if you happen to be in Firefox, you could use Q.async.

Q.async(function () {
    let username = yield getUsernameP();
    let password = yield getPasswordP();
    Q.return(loginP(username, password));
})().done();

Or in ES+generators:

Q.async(function *() {
    let username = yield getUsernameP();
    let password = yield getPasswordP();
    return loginP(username, password);
})().done();

@JamesMGreene
Copy link
Author

@kriskowal: Thanks for the info on Firefox advantages but this particular set of code is all for Node.js!

@JamesMGreene
Copy link
Author

@domenic:
Thanks, I grabbed 0.8.11 and updated all of my nbind calls to nfbinds. However, I am curious about the done method: if I have a fail handler in my promise chain, does it need to come before the done handler? Previously, my promise chain ended as .then(...).fail(...).end(); but I get the impression that it now needs to end as .fail(...).done(...);. Correct?

I assume I could still have it structured as before but just replace end with done (so .then(...).fail(...).done(); but it sounds like that would actually be a slightly sub-optimal setup due to the extra then hiding inside of then that would be used superfluously... right?

@JamesMGreene
Copy link
Author

FWIW, using .fail(...).done(...); feels very unnatural to me as the done handler is receiving a resolved promise value from my previous then but the fail handler is in the middle of the two, creating a mentally diverted/disjoint flow. Recommendations to fix that?

Where do you normally put your fail handler? Or, do you instead use the done handler's rejection argument (2nd function)? Would the done handler's rejection function receive failures from any point in the promise chain like fail does? I'm guessing not.

@domenic
Copy link

domenic commented Nov 26, 2012

No, fail shouldn't go before done; in that case: it does change the semantics.

.then(f1, r1, p1).fail(f2).end() should be replaced with .then(f1, r1, p1).fail(f2).done() or .then(f1, r2, p1).done(undefined, f2). I often cap with an empty .done(); I sometimes use .done(f) or sometimes .done(f, r).

Also: if you're writing only for Node you can use .catch instead of .fail (and .finally instead of .fin).

@JamesMGreene
Copy link
Author

Cool, I'll go with catch (definitely prefer its obviously semantic name over fail) and an empty done. Thanks again!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment