Redsandro
Redsandro

Reputation: 11356

Node.js Q promises, why use defer() when you can use this()?

I wanted to do something like:

somePromiseFunc(value1)
.then(function(value2, callback) {
    // insert the next then() into this function:
    funcWithCallback(callback);
})
.then(function(dronesYouAreLookingFor){
    // Have a party
})
.done();

It didn't work. I couldn't get it to work. I was advised to use defer() for this purpose.

Their own docs say we should use deferreds for callback-style functions. Although this is confusing because their famous flatten the pyramid example is all about callbacks, but the example is too abstract to follow.

Hence, I see a lot of people using defers and that is what I did:

somePromiseFunc(value1)
.then(function(value2) {
    var promise = q.defer();

    funcWithCallback(function(err, dronesYouAreLookingFor){
        if (!err)
            promise.resolve(dronesYouAreLookingFor);
        else
            promise.reject(new Error(err));
    });
    return promise.promise;
})
.then(function(dronesYouAreLookingFor){
    // Have a party
})
.done();

Until I found out through examining source code that this also works:

somePromiseFunc(value1)
.then(function(value2) {
    return function() {
        funcWithCallback(arguments[1]);
    };
})
.then(function(dronesYouAreLookingFor){
    // Have a party
})
.done();

Why should I not use this much simpler undocumented version?

Undocumented, because although this looks like what flatten the pyramid does, return function(){withCB(arguments[1])} works while return function(err, cb){withCB(cb)} does not.

Upvotes: 7

Views: 5777

Answers (1)

ForbesLindesay
ForbesLindesay

Reputation: 10712

It's not a legal way of using a promise library. As detailed in the promises spec that Q aims to comply with, anything you return from a .then callback that is not a promise should be passed directly through.

Essentially callback based code should be treated as legacy when you're using promises.

You have two basic options. If you use funcWithCallback lots of times you can do something like:

var promisedFunc = Q.nfbind(funcWithCallback);

somePromiseFunc(value1)
.then(function(value2) {
    return promisedFunc();
})
.then(function(dronesYouAreLookingFor){
    // Have a party
})
.done();

or if you need to pass arguments:

var promisedFunc = Q.nfbind(funcWithCallback);

somePromiseFunc(value1)
.then(function(value2) {
    return promisedFunc(value1, value2);
})
.then(function(dronesYouAreLookingFor){
    // Have a party
})
.done();

If you're only using it once you can do

somePromiseFunc(value1)
.then(function(value2) {
    return Q.nfcall(funcWithCallback);
})
.then(function(dronesYouAreLookingFor){
    // Have a party
})
.done();

or if you need to pass arguments:

somePromiseFunc(value1)
.then(function(value2) {
    return Q.nfcall(funcWithCallback, value1, value2);
})
.then(function(dronesYouAreLookingFor){
    // Have a party
})
.done();

Upvotes: 10

Related Questions