Creating node library that support both node callb

2019-05-14 18:40发布

问题:

I am creating a node module and I want to be able to support both node callback and Promise APIs. The library that I hear the best things about (mainly that is it the fastest) is bluebird. So after reading some docs and looking at some other libraries that are using bluebird, I thought this would be the cleanest way to get a method to support both node callback and Promise APIs:

this.isAllowed = function(role, resource, permission, callback) {
  var isAllowedAsync = bluebird.promisify(isAllowed);
  return isAllowedAsync(role, resource, permission).nodeify(callback);
};

However with this code, the callback is never executed. After some more research, I tried this:

this.isAllowed = function(role, resource, permission, callback) {
  return new bluebird(function (resolve, reject) {
    resolve(isAllowed(role, resource, permission));
  }).nodeify(callback);
};

With that code, both the node callback and Promise API works.

For reference, this is the isAllowed method:

var isAllowed = function(role, resource, permission) {
  if(!lists[role] || !lists[role][resource]) {
    return false;
  }

  return lists[role][resource].indexOf(permission) !== -1;
};

Am I doing something wrong in the first code example or is the second example the real way of getting what I am looking for?

回答1:

Your specific problem makes no sense (see my comment) so I'll just be generic. There are 2 ways to expose a dual promise/callback API.

First way is to have the same function support promises and callbacks at the same time, by returning a promise if callback parameter is not passed or using the callback if it is passed.

However this is hard to implement and can have some nasty problems when some arguments are optional.

To implement it, you do exactly the same thing as you would with a 100% promise function except you add a .nodeify at the end of the returned chain.

// Note however this doesn't work if some arguments before 
// `callback` are optional
function dualApi(..., callback) {
    // acting as if you would never support callbacks at all
    return getPromise()
           .then(...) 
           .then(...)
           .then(...)
            // .nodeify at the end of the chain, NOWHERE else
           .nodeify(callback)

}

The second way is to define a normal callback api, and then just call promisifyAll. This is very easy to implement, in fact there is almost no reason to do it at all because the user can so easily promisify the module themselves if they use bluebird.