async/flow series on node.js - node.js

Consider this code:
var async = require('async');
var a = function()
{
console.log("Hello ");
};
var b = function()
{
console.log("World");
};
async.series(
[
a,b
]
);
Output is
Hello
Why is World not part of the output?

The async.series function passes one callback to each of the methods that must be called before the next one is called. If you change your functions a and b to call the function it will work.
function a(done){
console.log('hello');
done(null, null); // err, value
}
function b(done){
console.log('world');
done(null, null); // err, value
}

For each method called in series it is passed a callback method which must be run, which you are ignoring in your example.
The docs say:
tasks - An array or object containing functions to run, each function
is passed a callback(err, result) it must call on completion with an
error err (which can be null) and an optional result value.
The reason why your code is stopping after the first method is that the callback isn't being run, and series assumed an error occurred and stopped running.
To fix this, you have to rewrite each method along these lines:
var b = function(callback)
{
console.log("World");
callback(null, null) // error, errorValue
};

Related

Nodejs - Using async.forEachOf to do a loop and return without a callback

I'm not making any calls to any server. I'm simply looping over an object and making some simple comparisons on the current item. I want to be able to use return instead of nesting my code inside a callback. By my current understanding of node.js, the below code should execute immediately and return the boolean.
Example:
function validate() {
var error = false;
var items = {
'item1': 'value1',
'item2': 'value2'
};
var eachItem = function(item, key, next) {
// do some simple comparisons
if (item !== 'value3') {error = true;}
next();
};
async.forEachOf(items, eachItem, function() {
// I prefer not to use callback(error), error is defined here
console.log('End Validate', error);
return error;
});
}
var thisError = validate();
console.log('After Validate', thisError); // thisError is undefined
The above does not work. I'm thinking because I'm using async.forEachOf. validate() is always undefined. However, when debugging, I notice that the boolean is defined before the next code is ran ('End Validate' shows up, then 'After Validate' does, which is the correct order of execution). Looks like it's simply not returning. Is there any way to return the boolean from the function in my above example without using a callback?
I do not want to use a for...in because I love the way async references the current item in the collection, and if I never need to, I can easily change my code with a callback in case I'm actually doing async operations.
Habits. The answer turns out to be very simple. I needed to define the return as the last line in the validate() function. It cannot be inside the async.forEachOf method.
The below is a working example.
function validate() {
var error = false;
var items = {
'item1': 'value1',
'item2': 'value2'
};
var eachItem = function(item, key, next) {
// do some simple comparisons
if (item !== 'value3') {error = true;}
next();
};
async.forEachOf(items, eachItem, function() {
// I prefer not to use callback(error), error is defined here
console.log('End Validate', error);
});
return error;
}
var thisError = validate();
console.log('After Validate', thisError); // thisError is defined

Node.js - Unable to use callback in if statement

Hi I am trying to execute a callback in a if statement but I get "TypeError: callback is not a function"
This is my code:
socket.on('authenticate', function (data, callback) {
// this works
callback("false");
// this doesn't work
if (data == "abc") {
callback("true");
}
});
Always check if callable function is passed, at least just do if(callback)
in Your problem there may be situation that clientside not waiting for callback (done emit call without passing callback argument).
Try this solution:
socket.on('authenticate', function (data, callback) {
console.debug('socket authenticate:', data); // for debug purposes
if (data == "abc") {
if(callback) { // callback may not be passed
callback(null, true); // keep in mind in callbacks first argument is error second is result
}
return; // return will prevent execution to go down, because most of times used for resulting call.
}
if(callback) { // callback may not be passed
callback("Not authenticated", false);
}
});

nodejs: force callback execution if method hangs

i have a situation where my asynchronus nodejs method from a third party library is taking too long. i want to set a timeout limit on this call and if it does not return within that timeout, i want a callback to happen with default(empty) values.
current code
wrapperfunct(data, function(value, err) {
//do everything with value or err
})
wrapperfunc(data, callback) {
thirdpartylib.getData(input, callback)
}
i am noticing that getData sometimes hangs, that prevents the callback from happening. i want a behavior than if getData does not call the callback method in specified time, i call callback with default values, say (null, null).
You can make your own timeout like this:
wrapperfunc(obj, timeout, data, callback) {
var done = false;
var timer = setTimeout(function() {
done = true;
// callback with both values null to signify a timeout
callback(null, null);
}, timeout);
obj.thirdpartylib.getData(input, function(err, data) {
if (!done) {
clearTimeout(timer);
done = true;
callback(err, data);
}
})
}
Note: The value of this in your proposed function was probably not correct so I substituted obj. You will either have to pass that value in or you will have to use some variable that is within scope for that.

How to return a function from callback?

If I have the following code:
var content;
var f = fs.readFile('./index.html', function read(err, data) {
if (err) {
throw err;
}
content = data;
return console.log(content);
});
f();
I got the following:
f();
^
TypeError: undefined is not a function
How can I do to return a function, which is not undefined?
My real issue, in a bigger context is the following https://gist.github.com/jrm2k6/5962230
You can't usefully return from within the callback to your code.
Using return inside the callback doesn't return a value to your code. fs.readFile() calls the callback itself so the return value is given to it. For your code to receive it, fs.readFile() would have to return the value it got from the callback, which it doesn't.
And, since fs.readFile() is asynchronous, it actually can't. Your code spans 2 different points in time:
"Present"
var content;
var f = fs.readFile('./index.html', /* ... */);
f();
"Future"
/* ... */
function read(err, data) {
if (err) {
throw err;
}
content = data;
return console.log(content);
}
/* ... */
You simply can't use a value from the "Future" in the "Present" -- or, at that point, the "Past."
This all generally leads to continuing the callback pattern rather than using return. Taking your "real" code:
var cheerioURLContent = function (url, callback) {
rest.get(url).on("complete", function (result) {
callback(cheerio.load(result));
});
};
cheerioURLContent('./index.html', function (t) {
console.log(t);
});
You can assign event handlers for custom events and trigger (emit) the events from within the callback. It's a bit hard to get your head around at first, but pretty elegant.
See Emitting event in Node.js for an example.

Invoking async.series inside async.series produces unpredictable output

Using caolan's async library for node.js, I've been trying to call a function that uses async.series inside another function that uses async.series, but I still can't get the functions to run in the correct order, as detailed below:
The terminal output shows the second function being called before the first, for no apparent reason:
The "sys" module is now called "util". It should have a similar interface.
Starting the second step in the series
Value of b: undefined
Invoking the function firstStep
the value of toObtain is: [object Object]
And here's the corresponding source code:
var im = require('imagemagick');
var async = require('async');
var toObtain;
var b;
async.series([
function (callback) {
//It appears that this function is being invoked after the second function.
//Why is this happening?
firstStep();
callback();
},
function (callback) {
//Why is the output of this function being displayed BEFORE the output of the function above? It's the opposite of the order in which I'm calling the functions.
console.log("Starting the second step in the series");
console.log("Value of b: " + b);
}]);
function firstStep(){
async.series([
function (next) { // step one - call the function that sets toObtain
im.identify('kittens.png', function (err, features) {
if (err) throw err;
console.log("Invoking the function firstStep");
toObtain = features;
//console.log(toObtain);
b = toObtain.height;
next(); // invoke the callback provided by async
});
},
function (next) { // step two - display it
console.log('the value of toObtain is: %s',toObtain.toString());
}]);
}
After about an hour of experimentation, I got it to work properly. I simply modified the firstStep function so that it takes a callback function as a parameter, and calls the callback at the end of the firstStep function.
var im = require('imagemagick');
var async = require('async');
var toObtain = false;
var b;
async.series([
function (callback) {
firstStep(callback); //the firstStep function takes a callback parameter and calls the callback when it finishes running. Now everything seems to be working as intended.
},
function (callback) {
console.log("Starting the second step in the series");
console.log("Value of b: " + b);
}]);
function firstStep(theCallback){
async.series([
function (next) { // step one - call the function that sets toObtain
im.identify('kittens.png', function (err, features) {
if (err) throw err;
console.log("Invoking the function firstStep");
toObtain = features;
//console.log(toObtain);
b = toObtain.height;
next(); // invoke the callback provided by async
});
},
function (next) { // step two - display it
console.log('the value of toObtain is: %s',toObtain.toString());
theCallback();
}]);
}

Resources