Create an api which accepts a callback, and also r

2019-07-22 17:17发布

问题:

So I'm trying to upgrade an existing api to support promises, but I want to maintain backwards compatibility. So, let's say this is my api:

module.exports = {

    deliverPost: function(callback) {

        someAsyncFunction(function(err) {

            if (err)
                console.log(err);

            callback(err);
        });
    }
}

That's great, I can call it and pass a callback, and everything works.

Now we do the same thing with promises:

var q = require('q');

module.exports = {

    deliverPost: function() {

        return q.nfcall(someAsyncFunction).catch(function(err) {

            console.log(err);
            throw err;
        });
    }
}

Great, now it returns a promise, but my problem is, any old clients of this api expect to be able to pass in a callback!

So what I really need is something like this:

var q = require('q');

module.exports = {

    deliverPost: function(callback) {

        return q.nfcall(someAsyncFunction).catch(function(err) {

            console.log(err);
            throw err;

        }).attachNodeStyleCallback(callback);
    }
}

So new callers can leverage the promise support, but everything still works if you pass in a callback.

This is a pattern used by, e.g. jQuery.ajax -- how can I do the same with Q.js?

Here's an implementation of attachNodeStyleCallback for reference:

q.makePromise.prototype.attachNodeStyleCallback = function(callback) {

    if (!callback)
        return this;

    return this.then(function(result) {

        callback(null, result);
        return result;

    }, function(err) {

        callback(err);
        throw err;
    })
}

回答1:

The answer is to use promise.nodeify:

var q = require('q');

module.exports = {

    deliverPost: function(callback) {

        return q.nfcall(someAsyncFunction).catch(function(err) {

            console.log(err);
            throw err;

        }).nodeify(callback);
    }
}


回答2:

You could just test for a callback and run the callback code if it is present:

var q = require('q');
module.exports = {

  deliverPost: function(callback) {
    if(typeof callback === 'function'){
      someAsyncFunction(function(err) {
        if (err)
          console.log(err);
        callback(err);
      });
    }else{
      return q.nfcall(someAsyncFunction).catch(function(err) {
        console.log(err);
        throw err;
      });
  }
}