I am new to Nodejs and need some guidance for writing better code. Here is my problem.
I have a function which is which I am using async water fall model. I want to call that function in a loop and break the loop if some thing goes wrong in the middle other wise notify some result at the end of for loop. But for some reason I am getting an undefined response.
function myFunc (arg1) {
async.waterfall(
[
function() {
//do something
callback(null, data);
},
function(data, callback) {
//do something
callback(null, 'done');
}
],
function(err, result) {
return {"error" : err, "res" : result};
}
}
//Here I am calling my function
for (var d in mydata) {
var retdata = myFunc (mydata[d]); //retdata has undefined in it as this line executes before the last function of water fall
if (retdata.error !== 200) {
return // break loop
}
}
//Other wise if every thing is fine nofify after the for loop end
console.log ("done");
In short what is the correct and best way of notify the result (if true) at the end or break loop when last function of waterfall gives error.
You can't use synchronous methods (like a for loop) and expect your code to wait till the asynchronous task completes. You can't use return to get data from an asynchronous function.
Here is a way to restructure your code using async.map. Take note of the callback structure. Also be sure you are referring to the async documentation.
//Async's methods take arrays:
var mydata = {a: 'foo', b: 'bar'};
var myarr;
for (var d in mydata) {
myarr.push(mydata[d]);
// Beware, you might get unwanted Object properties
// see e.g. http://stackoverflow.com/questions/3010840/loop-through-array-in-javascript/3010848#3010848
}
async.map(myarr, iterator, mapCallback);
function iterator(d, done){
// async.map will call this once per myarr element, until completion or error
myFunc(d, function(err, data){
done(err, data);
});
};
function mapCallback(err, mapped){
// async.map will call this after completion or error
if(err){
// Async ALREADY broke the loop for you.
// Execution doesn't continue if the iterator function callsback with an
// error.
};
console.log("Asynchronous result of passing mydata to myfunc:");
console.log(mapped);
// mapped is an array of returned data, in order, matching myarr.
};
function myFunc (arg1, callback) {
async.waterfall(
[
function(done) {
//do something
done(null, data);
},
function(data, done) {
//do something
done(null, 'done');
}
],
function(err, result) {
if (result !== 200) {
return callback('Non-200');
// This return is important to end execution so you don't call the callback twice
}
callback(err, result);
}
}
You are trying to mix both synchronous and async control flows. The problem is that your call to myFunc will return immediately before any of the waterfall functions inside myFunc executes.
Here is a real example that will work. It iterates through the array and terminates with an error if it sees a 5:
var async = require('async');
function myFunc(data, cb) {
async.waterfall(
[
function(callback) {
//do something
callback(null, data);
},
function(data, callback) {
//do something
if (data === 5) {
callback("Five", null); // Throw error if we see 5
} else {
callback(null, 'done');
}
}
],
function(err, result) {
cb(err, result);
}
);
}
var mydata = [1,2,3,4,5,6];
async.eachSeries(mydata, function(d, cb) {
console.log('Processing ' + d);
myFunc(d, cb);
}, function(err) {
// error happened in processing d
// handle error
console.log('Error ' + err);
});