So far I really like the deferred/promise model. On the client it lets me get data as early as I want to, but defer using the response until it’s convenient; maybe not until inside some event handler. I can also place a call to .fail() for any promise in a convenient place, even before I make a call for data. The Deferred object coordinates calling any registered fail function(s) if anything errors — that’s right, you can specify multiple handlers for the failure — and all the done, then and always functions that have been registered, when appropriate.
To do the same thing on the server, I found jQuery Deffered for nodejs. After requiring it
var Deferred = require( "JQDeferred" );
and with a little function in my application
function promise (query) {
var dfd = Deferred ();
query .run (function (err, doc) {
if (doc) {
if (doc.length > 0 || Object.keys(doc).length > 0) {
console .log ("found\n", util .inspect(query));
dfd .resolve (doc);
}
else {
console .log ("not found or no rows\n", util .inspect(query));
dfd .resolve (null);
}
}
else {
console .log ("error or no data object\n", util .inspect(query));
dfd.reject (err ? err : null);
}
});
return dfd .promise ();
}
Works for any Mongoose method that returns a query, like find, findOne. It’ll need to change to fold in the rest of my calls. In one function, I need to get 3 rows to verify something before I take action. Using jQuery Deferred and this promise function, dealing with 3 asynchronous calls with very little code looks like
var CloseAll = function (query, resp) {
Deferred .when (
promise (modelA .findOne ({modelAkey:query.body.A})),
promise (modelB .findOne ({modelBkey:query.body.B})),
promise (modelC .findOne ({modelCkey:query.body.C})))
.fail (function (err) { resp .send (_.extend (query.body, err), 500); })
.done (function (dataA, dataB, dataC) {
now do stuff that require all 3 things
Pretty sweet.
Really cool, this has helped me clean up my controllers, thanks Grant!
I’m pleased that it could help and I appreciate the comment.