Using Q/promises vs callbacks

Viewed 1302

I'm using the Q library in nodejs and haven't worked too much with promises in the past, but I have semi complex logic that requires lots of nesting and thought Q would be a good solution, however I'm finding that it seems to be almost the same as just "callback hell".

Basically I have say 5 methods, all which require data from the previous or one of the previous. Here's an example:

We start with some binary data that has a sha1 hash generated based on the binary.

var data = {
    hash : "XXX"
  , binary: ''
}

First we want to see if we already have this, using this method:

findItemByHash(hash)

If we don't have it, we need to save it, using:

saveItem(hash)

Now we need to associate this to a user, but not only the results of the save. There's now a much larger hierarchy that we associate, so we need to get that first, doing:

getItemHierarchy(item_id), we use the item_id returned from our previous saveItem

Now, we can "copy" these results to a user:

saveUserHierarchy(hierarchy)

Now we're done, however, this assumes the item didn't exist yet. So we need to handle a case where the item did exist. This would be:

We need to check if the user may aleady have this:

getUserItemByItemId(item_id) - item_id was returned from findItemByHash

If it exists, we're done.

If it doesn't:

getItemHierarchy(item_id)

Then

saveUserHierarchy(hierarchy)

Ok, so right now we have callbacks that do these checks, which is fine. But we need to handle errors in each case along the way. That's fine too, just adds to the mess. Really, if any part of the flow throws an error or rejects then it can stop and just handle it in a single place.

Now with Q, we could do something like this:

findItemByHash(hash).then(function(res) {

    if (!res) {

     return saveItem(hash).then(function(item) {
        return getItemHierarchy(item.id).then(function(hierarchy) {
            return saveUserHierarchy(hierarchy);
        });
     })

    } else {

      return getUserItemByItemId(res.id).then(function(user_item) {

         if (user_item) {
            return user_item;
         } 

        return getItemHierarchy(res.id).then(function(hierarchy) {
            return saveUserHierarchy(hierarchy);
        });

      });

    }
})
//I think this will only handle the reject for findItemByHash?
.fail(function(err) {
   console.log(err);
})
.done();

So, I guess my question is this. Are there better ways to handle this in Q?

Thanks!

1 Answers
Related