使用回调/承诺实现使javascript函数始终返回一个promise

时间:2016-10-04 11:24:37

标签: javascript node.js asynchronous promise bluebird

我正在尝试使用异步身份验证处理程序,该处理程序可以具有回调或承诺的实现。范围是包装此函数以便始终返回promise,因此我可以使用它进一步回调/保证不可知。

如果有人可以为这些场景提供一些帮助,我将非常感激,其中一个例子就是现实生活。

如果功能如下:

function getData(id, callback) {
  var deferred = Q.defer();
  apiCall('/path/to/id', function (err, data) {
    if (err) deferred.reject(new Error(err));
    //do something with data
    deferred.resolve(processedData);
  }
  deferred.promise.nodeify(callback);
  return deferred.promise;
}

我希望以这种方式使用.fromCallback

function myProcessedDataFunction(id) {
  return Promise.fromCallback(function (callback) {
    return getData(id, callback);
  }, {multiArgs: true});
}

这会有用吗? myProcessedDataFunction会返回正确的承诺吗?

现实世界的例子是:

我有一个身份验证处理程序,可能会或可能不会使用回调函数实现,同时可以使用promises实现;或者它可能返回真/假值;

function authHandlerImplementation1(username, password) { 
  return (username === 'validUsername' && password === 'validPassword');
}

function authHandlerImplementation2(username, password, callback) {
  apiCall('/path/to/authorization', function (err, result) {
    if (err) return callback(err, null);
    callback(null, result);
  });
}

function authHandlerImplementation3(username, password) {
  return new Promise(function (reject, resolve) {
    apiCall('/path/to/authorization', function (err, result) { 
      if (err) return reject(err);
      resove(result);
    });
  });
}

function authHandlerImplementation4(username, password, callback) { 
  var deferred = Q.defer();
  apiCall('/path/to/id', function (err, data) {
    if (err) deferred.reject(new Error(err));
    //do something with data
    deferred.resolve(processedData);
  }
  deferred.promise.nodeify(callback);
  return deferred.promise;
}

我将尝试第5个蓝鸟实施。

function authHandlerImplementation5(username, password, callback) { 
  return apiCall('/path/to/id', callback).asCallback(callback); // I hope this is the right way to do it (correct me if I'm wrong, please)
}

我的checkAuth函数使用authHandler实现,并希望与回调/承诺无关。

function checkAuth(username, password) { 
  var self = this;
  return Promise.fromCallback(function(callback) { 
    return self.authHandler(username, password, callback); 
  }, {multiArgs: true});
}

如果authHandlerImplementation不使用回调(只返回一个值)(implementation1),checkAuth挂起,没有任何反应,我的测试失败。

是否有任何Bluebird方法可以将任何类型的authHandler实现包装到promise中(简单的返回,回调或promise实现)?

2 个答案:

答案 0 :(得分:2)

不,Bluebird没有这样的实用程序。如果你将它们作为API提供,那么支持回调和promises是很好的,但是当你需要使用API​​时却不是这样 - 区分方法是否需要回调或返回promises或者两者都不可能来自外部,并编写代码来动态地计算它(每次通话)都可能,但很尴尬。

Bluebird 有一个实用程序包含可能返回,抛出或返回一个promise的函数,它被称为Promise.method(并且还有Promise.try立即调用它)。

如果他们想要传递一个异步的auth-handler,我建议强制你的调用者使用promises。如果他们只有一个基于回调的版本,他们仍然可以将它自己包装在Promise.promisify中,然后再提供给你。

答案 1 :(得分:0)

我尝试了一些东西,并且设法让它发挥作用。我将在下面提供我尝试过的方法的详细信息。该方案适用于json-rpc 2.0服务器实现,该实现接收authHandler函数实现,以检查请求中提供的凭据的有效性。

更新:
在authHandler上使用Promise.method
var promisifiedAuthHandler = Promise.method(self.authHandler);适用于authHandler的同步实现。
回调实现失败。

在Promise.method中包含的authHandler上使用Promise.promisify适用于回调实现
var promisifiedAuthHandler = Promise.promisify(Promise.method(self.authHandler));
无法进行同步实施。

为authHandler提供回调(即使它在实现中不使用它)适用于所有方法。它是这样的(写一般情况,这是使用ES5-Class node module编写的模块的一部分):

function _checkAuth(req) {
  var self = this;
  var credentials = self._getCredentials(req);
  var promisifiedAuthHandler = Promise.method(self.authHandler); // for the sync implementation

  switch (authType) {
  // general case, let's say, there are several types
  // will just write one as an example.
  case Authorization.WHATEVERTYPE: 
    return promisifiedAuthHandler(credentials, function callback(err, result) {
      if (err) return Promise.reject(err);
      return Promise.resolve(result);
    }
  }
}

和server.enableCookie / JWT / BasicAuth处理程序可以用上面提到的三种方式实现:sync / callback / promise;如下:

server.enableCookieAuth(function (cookie) {
  return (cookie === validCookieValue);
});

server.enableCookieAuth(function (cookie, callback) { 
  apiCall('path/to/auth', function(err, result) { 
    // apiCall could have a promise implementation, as well, and could 
    // be used with .then/.catch, but this is not that important here, since we care 
    // about the handler implementation)
    if (err) return callback(err, null);
    callback(null, result); // can be returned
  }
});

server.enableCookieAuth(function (cookie) {
  // let's write the apiCall with promise handling, since we mentioned it above
  return apiCall('path/to/auth').then(function (result) {
    return Promise.resolve(result);
  }).catch(function (err) {
    return Promise.reject(err);
  });
});

现在,我们可以在内部使用我们的_checkAuth函数,只使用promises,与authHandler函数实现无关。如:

handleHttp: function(req, res) {
  var self = this;
  // ...other processing
  self._checkAuth(req).then(function (result) {
    // check if the user is authed or not 
    if (result) {
      // further process the request
    } else { 
      // handle unauthorized request
    }
  }).catch(function (err) {
     // handle internal server or api call (or whatever) error 
  });
}

诀窍是用promise实现编写回调函数。我们总是为authHandler提供一个回调实现,即使authHandler没有使用它。这样,如果auth处理程序实现使用回调样式实现,我们总是确保它返回一个promise。

欢迎所有评论,我想听听有关此事的一些意见!

感谢您的及时回复!