I have some code that I'd written using this pattern with Step.js. In this case, talking to MongoDB in Node:
Step(
function connectToDatabaseWithAuthorization() {
mongodb.connect(mongoConnectURI, this);
},
function getCommitCollection(err, conn) {
if (err) handleResErr(res, err);
conn.collection('commits', this);
},
function addCommitToCollection(err, coll) {
if (err) handleResErr(res, err);
var commit = JSON.parse(req.param('commit', null));
commit.commit_date = requestTime;
commit.commit_id = common.makeIdFromCommit(commit);
coll.insert(commit, {safe: true}, this);
},
function respondWithShowAndVerifyUrlsInJson(err, records) {
if (err) handleResErr(res, err);
res.json({
commit_date: records[0].commit_date
});
}
)
When I went to update my Node libraries, I noticed Step wasn't getting much attention or undergoing much development. And I wasn't happy about the error handling being spread into each function in the steps.
So I went to research modern alternatives, and Async.js seemed more popular. But when I asked about how to convert it, someone suggested I look into Q Promises instead.
I came up with this transformation, which seems to work:
Q.try(function() {
return Q.ninvoke(mongodb, 'connect', mongoConnectURI);
}).then(function (conn) {
return Q.ninvoke(conn, 'collection', 'commits');
}).then(function (coll) {
var commit = JSON.parse(req.param('commit', null));
commit.commit_date = requestTime;
commit.commit_id = common.makeIdFromCommit(commit);
return Q.ninvoke(coll, 'insert', commit, {safe: true});
}).then(function (records) {
res.json({
commit_date: records[0].commit_date
});
}).catch(function (err) {
handleResErr(res, err);
});
Not a large piece of code, but I could use a sanity check. I was having problems with figuring out if I should be using .done()
in there somewhere, and also I couldn't get .finally
to work. If I put it on the end of the chain, it ran after the first promise and not after all of them. :-/
While I mostly think the generality makes it an improvement, it does really obscure the method calls. Q.ninvoke(mongodb, 'connect' mongoConnectURI)
is quite a bit uglier than mongodb.connect(mongoConnectURI)
. Have people made some better way to do mongodb calls with promises than this?