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.
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.
I already sad 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?).