我当前正在将q与Node.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有专门的帮助器功能用于与节点回调接口。
您可以将代码简化为
count: function(){
return Q.nfcall(User.count);
},
findAll: function(){
return Q.nfcall(User.find, {});
}
如果这些方法依赖于它们的this
值,则可以使用Q.ninvoke(User, "count")
和Q.ninvoke(User, "find", {})
。
通过使用Q的函数/方法绑定:,您甚至可以将其推向更高的极端,完全避免函数表达式
count: Q.nfbind(User.count),
findAll: Q.nfbind(User.find, {})
或者具有this
值:
count: Q.nbind(User.count, User),
findAll: Q.nbind(User.find, User, {})
但是请注意,使用这些解决方案,您需要确保count
和findAll
的调用参数为零。
注意:Q有下面的内置版本,所以如果您使用Q(就像OP一样),请参阅Bergi的答案。如果您正在使用其他promise lib,请查看它是否使用;如果没有,请参见下文。
<小时>您可以为自己提供一个实用函数,该函数封装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
拒绝promise,要么使用在err
之后得到的参数数组解析它。可以与所有以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)
}
小时>