0

I have a task, and if it's been done, already, I need to skip it, and if it hasn't, I need to perform it. The task is asynchonous. After this, I need to do the same check for another task, and possibly perform it...

if(!taskStatus.complete[x])
  asyncTasks[x](function(result){
    if(!taskStatus.complete[y])
      asyncTasks[y](function(result){
        stow(result);
      });
  });
if(!taskStatus.complete[y])
  asyncTasks[y](function(result){
    stow(result);
  });

In other words, the second task needs to be performed regardless of whether or not the first gets done, but if the first is to be done, the second cannot happen until after it finishes.

My code has repeated itself quite a bit here, which is generally a very bad thing. Is it unavoidable for Node's hipness? Is Node too hip to be DRY?

user2958725
  • 1,355
  • 3
  • 12
  • 16

1 Answers1

1

You should into promises (here is a good library that implements promises). They allow you to elegantly represent dependencies between asynchronous functions of your code.

Provided that you convert your functions to use promises, here is an example for your particular use case:

getSomeX()
.then(getSomeY)
.then(function(result) {
    stow(result);
})

This nicely shows that you want to call stow() only when Y is done, and that Y needs X first.

Here is an example (and corresponding tutorial, subsection Using Deferreds) on how you could convert your functions to use promises:

var Q = require('q');
var getSomeX = function() {
    var deferred = Q.deferred();
    asyncTasks[x](function (result) {
        deferred.resolve(result);
    });
    return deferred.promise;
}

Edit: You can also use Q's ability to automatically transform an asynchronous function that respects Node's usual callback style (err, result) with the denodeify function:

var getSomeX = Q.denodeify(asyncTasks[x]);
Paul Mougel
  • 16,728
  • 6
  • 57
  • 64
  • Please don't use deferreds, the code is a waste of space and buggy because you need to manually propagate all error kinds which kinda defeats the point of using promises in the first place. Instead if some api uses callback convention, you can trivially turn it into promise API by using the `denodeify/promisify` function of your promise library. In bluebird it takes 3 lines to turn node-mysql and redis into robust promise APIs as if they were designed for that to begin with. Doing that manually using deferreds for each function in those libraries would have taken thousands of lines. – Esailija Nov 16 '13 at 19:15
  • I added a small `denodeify` example in the answer. I didn't mention it at first because OP's asynchronous function don't respect standard Node asynchronous style: they don't return (err, res). But this is a fair point indeed. – Paul Mougel Nov 17 '13 at 00:57