在 node.js 中使用 q 时如何删除样板代码

How to remove the boilerplate code when using q in node.js

我目前正在使用 qNode.js。我所有的模型都使用 q 的承诺。后来才知道这样写了一大堆样板代码

count: function(){
  var deferred = Q.defer()
  User.count(function(err,count){
    if(err)
      deferred.reject(err)
    else
      deferred.resolve(count)
  })
  return deferred.promise;
},
findAll: function(){
  var deferred = Q.defer()
  User.find({}, function(err,users){
    if(err)
      deferred.reject(err)
    else
      deferred.resolve(users)
  })
  return deferred.promise;
}

有没有办法删除这个样板代码?

注意: Q 具有以下内置版本,因此如果您正在使用 Q(如 OP 一样),请参阅 。如果您正在使用其他一些 promise 库,请查看是否可以;如果没有,请参阅下文。


您可以给自己一个实用函数来包装 Node 风格的调用并将它们转化为 promise(但请继续阅读),所以:

count: function() {
  return makePromise(User.count)
}

makePromise 看起来像

function makePromise(f) {
  var deferred = Q.defer()
  var args = Array.prototype.slice.call(arguments)
  args[0] = function(err) {
    if(err)
      deferred.reject(err)
    else
      deferred.resolve(Array.prototype.slice.call(arguments, 1))
  }
  f.apply(null, args)
  return deferred.promise
}

(我正在尝试遵循您的惯例,即 ASI 将更正的 ;

它调用你给它的函数,传递任何进一步的参数,当它得到响应时要么使用 err 拒绝承诺,要么使用它在 [= 之后得到的参数数组解析它16=]。可以与所有以 err 作为第一个参数调用回调的 Node 风格函数一起使用。

但是,有人已经为您完成了:promisify :-) 我很确定至少还有一个。

稍微复杂一点的版本将支持选择性地预先给出 thisArg

function makePromise(obj, f) {
  var deferred = Q.defer()
  var args, func, thisArg;
  if (typeof obj === "function") {
    thisArg = null
    func = obj
    args = Array.prototype.slice.call(arguments)
  } else {
    thisArg = obj
    func = f
    args = Array.prototype.slice.call(arguments, 1)
  }
  args[0] = function(err) {
    if(err)
      deferred.reject(err)
    else
      deferred.resolve(Array.prototype.slice.call(arguments, 1))
  }
  func.apply(thisArg, args)
  return deferred.promise
}

那么如果User.count需要用this = User调用:

count: function() {
  return makePromise(User, User.count)
}

Is there a way remove this boilerplate code?

是的,Q 有 dedicated helper functions for interfacing with node callbacks

您可以将代码简化为

count: function(){
  return Q.nfcall(User.count);
},
findAll: function(){
  return Q.nfcall(User.find, {});
}

如果这些方法依赖于它们的 this 值,您可以使用 Q.ninvoke(User, "count")Q.ninvoke(User, "find", {})

您甚至可以使用 Q 的 function/method 绑定将其推向更高的极端并完全避免函数表达式:

count: Q.nfbind(User.count),
findAll: Q.nfbind(User.find, {})

this 值:

count: Q.nbind(User.count, User),
findAll: Q.nbind(User.find, User, {})

但是请注意,对于这些解决方案,您需要确保 countfindAll 以零参数调用。