2

I got confused with async nature of node.js. I'm writing a small project in it and my previous (sync) programming experience gets in the way.

How should I decide if/where to write async code?

For example I've got a model with fields, where each has some validation rules:

model = { title: text_validation, 
  subtitle: text_validation }

text_validation = { max_len: 10,
  required: true,
  url: true }

When I validate the model, I iterate through all fields checking if rules pass - these are really quick functions.

Model.validate = function() {
  validator = {};
  fields = Object.keys(Model);
  fields.forEach(function(field) {
    validator[field_name] = field.validate();
  });
}

Field.validate = function() {
  validator = [];
  rules.forEach(function(rule) {
    if (rule is not valid)
      validator.push(rule)
  });

  return validator;
}

Should I use callbacks with such short and quick iterations?

Where is the limit here? Should node.js be always async or can I allow sync loops or w/e if it's quick enough? Please, if possible refer to examples when and where to use sync/async.

4
  • 3
    Using callbacks is not the same thing as being asynchronous. Making a simple loop asynchronous is not an easy task (look at process.nextTick) and definetly there is no serious advantage of doing that in most cases. Unless your loop is taking really long time. Commented Jun 27, 2012 at 14:17
  • Thanks for your answer. What do you mean by really long time? ;) Commented Jun 27, 2012 at 16:08
  • Actually I don't know. :) I've never faced such a long time to bother. Commented Jun 27, 2012 at 16:45
  • If you can actually notice it, it is too long. Commented Jun 27, 2012 at 20:22

2 Answers 2

6

You probably shouldn't. In most cases, you need async logic only when you're waiting for something from outside your application (mostly file, database and network operations). Delaying in-application code asynchronously will give you no performance advantage, as your code will still need to run at some point.

Sign up to request clarification or add additional context in comments.

2 Comments

It's not about performance. It's about high availability. If the loop is taking long time, then all other users are waiting (the server is basically blocked). Making it asynchronous allows other users to interact with the server. Of course the price has to be paid: the loop will take even more time.
If the loop takes too much time (i.e. it is computationally intensive), you might fork it into a separate process and pass its result via child.send(). Other than that, breaking up your loop into asynchronous iterations will be overly complicated.
2

I already said that in comment, but I think it is a good idea to give examples as well.

The concepts of callback and asynchrounous operations are different, although related. The forEach loop you are using is not asynchronous at all. Here's how more or less the definition of forEach looks:

Array.prototype.forEach = function(callback) {
    var l = this.length;
    for (var i = 0; i < l; i++)
        callback(this[i], i);
};

As you can see there is nothing asynchronous in this. The callback is executed in a loop step after step, synchronously.

So how to make the loop asynchronous? Well, you could try this:

Array.prototype.asyncForEach = function(applier, finished) {
    var self = this;
    var l = self.length;
    var call = function(i) {
        process.nextTick(function() {
            applier(self[i], i);
            if (i == l-1)
                finished();
            else
                call(i+1);
        });
    }
    call(0);
};

And you can use it like this:

var x = [1,2,3,4,5,6,7,8,9,10];
x.asyncForEach(function(el, index) {
    /* apply function to each el and index */
    console.log(el);
}, function() {
    /* This will be called when the loop finishes! */
    console.log('Finished!');
});
/* Let us check whether the loop is really asynchronous.
   The following code should fire BEFORE loop! */
console.log('Is it asynchronous?');

As you can see, it is not see as easy and simple as forEach. But this allows other code to be running between iterations of the loop (magic of the process.nextTick method). So you gain High Availability, but the cost is that it will take even more time for the loop to finish. Note that modifying the array between iterations is possible and it will likely result in crashing your app. :D

As I said in comment: I've never ever seen a loop working so long that it actually needed to be turned to asynchronous one. And I've worked with some market data which I processed alot (although with Python, not JavaScript - this might be a reason). And as lanzz commented, if the loop takes too much time, forking it may be a good idea. Or creating a WebService (or Node.JS addon) written in some efficient language (C?).

6 Comments

Thanks for this, but I've got some other questions popping up right now. So as far as I understand: callback are pretty much required for async code, because we want the event loop to fire them up somewhere in the future (after our async stuff finishes). So if I have a blocking foreach loop, then doing async stuff inside it won't unblock the thread, but when I use forEach from 'async' module and put fs.readFile there, then it will be non-blocking?
@muchzill4 I've just looked at the async's forEach source code. It looks like it is working a bit different then the code I've shown you. It is calling nextTick for every element in array (in a synchronous loop) rather then calling nextTick after the previous tick finished the job. This means that there cannot be any code between any two iterations of async's loop, i.e. async's forEach waits until the server finished all other "jobs" (other defined ticks at the time of calling) and fires synchronously a loop. This is how it looks for me at least.
Now you made me totally confused. Where does async's forEach call nextTick? Are you talking about the same async as I do? github.com/caolan/async/blob/master/lib/async.js
Ups, sorry. I only looked for 1 sec (I was in work at the moment, hehe) and somehow I was sure I've seen nextTick there. But you're right, there is nothing asynchronous there. Then this line (at they're main page) since this function applies the iterator to each item in parallel there is no guarantee that the iterator functions will complete in order is a lie. O_o
I asked (you too probably? ;)) the author of async about that and that's what he said: async.forEach is the same as forEach but it provides a mechanism to let you know when processing of the asynchronous tasks have completed (using callbacks). Using the standard forEach would run the functions in the same order, but would give you no indication of when they completed and whether an error occurred. async.forEach does not magically make synchronous code asynchronous. It's just a tool to help you keep track of asynchronous operations and manage when they run.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.