Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 847
Redsandro Avatar asked Jan 22 '13 22:01

Redsandro


1 Answers

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();
like image 175
ForbesLindesay Avatar answered Oct 22 '22 17:10

ForbesLindesay