I am currently using q with Node.js
. All my models use the promises from q
. Later I realized writing a lot of boilerplate code like this
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;
}
Is there a way remove this boilerplate code?
Is there a way remove this boilerplate code?
Yes, Q has dedicated helper functions for interfacing with node callbacks .
You can simplify your code to
count: function(){
return Q.nfcall(User.count);
},
findAll: function(){
return Q.nfcall(User.find, {});
}
If those methods rely on their this
value, you can use Q.ninvoke(User, "count")
and Q.ninvoke(User, "find", {})
.
You can even take this to a higher extreme and avoid the function expression completely, by using Q's function/method binding:
count: Q.nfbind(User.count),
findAll: Q.nfbind(User.find, {})
or with a this
value:
count: Q.nbind(User.count, User),
findAll: Q.nbind(User.find, User, {})
But notice that with these solutions you need to ensure that count
and findAll
are called with zero arguments.
Note: Q has a built-in version of the below, so if you're using Q (as the OP is), see Bergi's answer . If you're using some other promise lib, see if it does; if not, see below.
You can give yourself a utility function that wraps Node-style calls and turns them into promises (but keep reading), so:
count: function() {
return makePromise(User.count)
}
makePromise
would look something like
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
}
(I'm trying to follow your convention of leaving off ;
that ASI will correct)
That calls the function you gave it, passing along any further arguments, and when it gets the response either rejects the promise using err
, or resolves it using an array of the arguments it got after err
. Could be used with all Node-style functions that call their callbacks with err
as the first argument.
But , someone's already done that for you: promisify
:-) I'm fairly sure there's at least one other one as well.
A slightly more complex version would support optionally giving a thisArg
up front:
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
}
Then if User.count
needs to be called with this
= User
:
count: function() {
return makePromise(User, User.count)
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.