Final callback not showing any result - node.js

I am using async series to run 2 functions takes2Seconds and function takes5Seconds.Why the final callback not showing any result?
var async = require('async'),
operations = [];
operations.push(takes2Seconds(1,function(){}));
operations.push(takes5seconds(2,function(){}));
async.series(operations, function (err, results) {
if(err){return err;}
console.log(results);
});
function takes2Seconds(a,callback) {
results='Took 2 sec'+a;
callback(null, results);
}
function takes5seconds(b,callback) {
results='Took 5sec'+b;
callback(null, results);
}

It looks like you are pushing two undefined values to operations.
When running async.series the operations array needs to contain function(s) that has callback as it's parameter.
When you do operations.push(takes2Seconds(1, function() {})); you are invoking the takes2Seconds function straight away, and because there is no return statement in the takes2Seconds function, it is pushing undefined to the operations array.
Below, I have added a return statement into your takesXSeconds functions. They now return a function with callback as the parameter, and the returned function gets pushed to the operations array.
I have also remove the callback param from takesXSeconds as it is not needed at this point.
When running async.series(...) now, each function (which we returned from takesXSeconds) gets invoked.
var async = require('async'),
operations = [];
operations.push(takes2Seconds(1));
operations.push(takes5seconds(2));
async.series(operations, function (err, results) {
if(err){return err;}
console.log(results);
});
function takes2Seconds(a) {
var results='Took 2 sec'+a;
return function(callback) {
callback(null, results);
}
}
function takes5seconds(b) {
var results='Took 5sec'+b;
return function(callback) {
callback(null, results);
}
}

First your takes2Seconds function executed then function takes5seconds executed.
var takes2Seconds = function (a, callback) {//first this function executed
results = 'Took 2 sec' + a;
callback(null, results);
};
async.eachSeries(takes2Seconds, takes5seconds, function (err) {
if (err) {
res.json({status: 0, msg: "OOPS! How is this possible?"});
}
res.json("Series Processing Done");
})
var takes5seconds = function (b, callback) { // second this function executed
results = 'Took 5sec' + b;
callback(null, results);
}

Related

Hard time uderstaning async.parallel in node

I have this function in the controller
router.post('/', function(req, res, next) {
if (req.user.isPremium == false) {
// Free user - Single report
let website = req.body.website0;
let builtWithCall = `https://api.builtwith.com/free1/api.json?KEY=APIKEY&LOOKUP=${website}`;
let pagespeedCall = `https://www.googleapis.com/pagespeedonline/v4/runPagespeed?url=https://${website}&strategy=mobile&key=APIKEY`;
// curl 'https://www.googleapis.com/pagespeedonline/v4/runPagespeed?url=https://georgiancollege.ca&strategy=mobile&key=APIKEY'
var calls = [];
calls.push(function(callback) {
// First call
https.get(builtWithCall, function(resource) {
resource.setEncoding('utf8');
resource.on('data', function(data) {
// console.log('BuiltWith received', data);
});
});
});
calls.push(function(callback) {
// second call
https.get(pagespeedCall, function(resource) {
resource.setEncoding('utf8');
resource.on('data', function(data) {
// console.log(data);
});
});
});
} else {
// Premium user - comparison report
let websites = [];
}
async.parallel(calls, function(err, results) {
if(err){
console.log(err);
}
console.log('async callback ', results);
res.render('/generated-report', {
title: 'Report',
data: {},
});
});
});
I am trying to run several async API calls at once. The problem is, when I try to run them like this
async.parallel(calls, function(err, results) {
if(err){
console.log(err);
}
console.log('async callback ', results);
res.render('/generated-report', {
title: 'Report',
data: {},
});
});
the console doesn't log anything.
When I do the console log here though
function(callback) {
// second call
https.get(pagespeedCall, function(resource) {
resource.setEncoding('utf8');
resource.on('data', function(data) {
// console.log(data);
});
});
}
it logs the response. The pageSpeed one gets in a weird loop and repeats itself multiple times, but at least it works.
Now what am I doing wrong with the async.parallel part? Also what is this callback in function(callback) {?
EDIT:
This is the new version of the anonymous function:
function(callback) {
// second call
var results;
https.get(pagespeedCall, function(resource) {
resource.setEncoding('utf8');
resource.on('data', function(data) {
results += data;
// console.log(data);
});
resource.on('end', function(data) {
callback(null, data);
});
resource.on('error', function(err) {
callback(err);
});
});
}
You need to call the passed in callback. Looking at your one parallel function you are not calling callback(). I'll assume your resource object has an end & error
function(callback) {
// second call
var results;
https.get(pagespeedCall, function(resource) {
resource.setEncoding('utf8');
resource.on('data', function(data) {
results += data;
// console.log(data);
});
resource.on('end' function() {
callback(null, results);
});
resource.on('error' function(err) {
callback(err);
});
});
}
How async.parallel works is all the functions called must in turn call the passed in callback function; in your case that is callback.
Once each function in the parallel calls callback then and only then will the final function be called, which is the function you defined as function(err, results) {...}.
There is one caveat, if in the callback call you pass non-null for the first argument then that final function will be called immediately where you should handle that error if it happens.

NodeJs Async Parallel: 'undefined is not a function'

I'm trying to wrap my head around the async library, but I'm pretty wobbly in NodeJs and I can't figure out async.parallel. The code below produces error TypeError: undefined is not a function on the line where the parallel tasks are to be executed. Am I correct in that tasks to be run in async.parallel should have a callback() when they are done? (irrelevant parts of the function are redacted)
function scrapeTorrents(url, callback) {
request(url, function(err, res, body) {
if(err) {
callback(err, null);
return;
}
var $ = cheerio.load(body);
var results = [];
var asyncTasks = [];
$('span.title').each(function(i, element){
// scrape basic info
var show = {title: info.title, year: info.year};
asyncTasks.push(
getOmdbInfo(show, function (err, res) {
if (res) {
omdbInfo = res;
results.push({
// add basic info and Omdb info
});
}
callback();
})
);
});
async.parallel(asyncTasks, function(){
callback(null, results);
});
});
}
In the section where you define async tasks, be sure to specify a closure with a parameter method to call once the task is complete (named differently than callback so as to avoid hoisting).
asyncTasks.push(
function (done) {
getOmdbInfo(show, function (err, res) {
if (err) {
return done(err);
}
if (res) {
omdbInfo = res;
results.push({
// add basic info and Omdb info
});
}
return done();
})
}
);

Trying to understand async.forEach

I am currently trying to learn the async module for node.js. Below is an example demonstrating how to use async.forEach.
var async = require('async'),
request = require('request');
var results = {};
function done(err) {
if (err) {
throw err;
}
console.log('done! results: %j', results);
}
var collection = [1, 2, 3, 4];
function iterator(value, callback) {
request.post({
uri: 'http://localhost:8080',
body: JSON.stringify(value)
},
function(err, res, body) {
if (err) {
return callback(err);
}
results[value] = JSON.parse(body);
callback();
});
}
async.forEach(collection, iterator, done);
So async.forEach iterated through each element in the collection, and each element is then passed into "value" in the iterator function...but I don't really understand whats being passed into callback? (which is then executed at the end of iterator)
It will receive an array of the results of the individual operations – whatever you pass to the callback.
Since you don't pass anything to the callback, it will receive an array of undefined.

Callback not getting called while using async.series

I have the following code, where i am calling a callback after my async task is completed:
var async = require("async");
function _callback(err, result){
if(err) console.log('Error Occurred');
console.log('Callback called');
console.dir(result);
}
function tasks() {
console.log('Start executing tasks');
var tasks = [];
var result = {};
tasks.push(function(_callback) {
console.log('Getting some data');
_callback(null, result);
});
tasks.push(function(_callback) {
console.log('Second function called');
_callback(null, result);
});
async.series(tasks, function(){
console.log('All done');
});
}
tasks();
I have checked against the syntax expected in the async library. Code looks similar to me.
Can someone point out whats needs to be changed here.
Try it like this:
var async = require("async");
function _callback(err, result){
if(err) console.log('Error Occurred');
console.log('Callback called');
console.dir(result);
}
function tasks() {
console.log('Start executing tasks');
var tasks = [];
var result = {};
tasks.push(function(next) {
console.log('Getting some data');
next(null, result);
});
tasks.push(function(_callback) {
console.log('Second function called');
next(null, result);
});
async.series(tasks, function(err, result){
console.log('All done');
_callback(err, result);
});
}
tasks();
Async gives every single task a callback which you need to call to let async now that this task finished.
After all tasks are finished you can call your callback.
If you want your callback to get called after every single task is finished just add before every
next(null, result) also an _callback(null, result)
The reason that wouldn't work on your implementation is that you overwrite the global _callback method with the argument that has the same name.
Hope that makes sense :)
As it stands in your code right now, the _callback function you define above should never get called, as the _callback in the tasks functions is scope to the one passed by async.
// this will never get called
function _callback(err, result){
if(err) console.log('Error Occurred');
console.log('Callback called');
console.dir(result);
}
function tasks() {
console.log('Start executing tasks');
var tasks = [];
tasks.push(function(_callback) { // the _callback here overrides the one above for this closure
console.log('Getting some data');
_callback(null, result);
});
// ... more tasks
async.series(tasks, function(){
console.log('All done');
});
}
If you want to reuse the logic in your _callback function, I'd recommend passing it the async callback as a parameter:
// rename some functions to avoid silly js scoping mysteries
function myCallback(err, result, asyncCallback){
// shared logic here
if(err) console.log('Error Occurred');
console.log('Callback called');
console.dir(result);
asyncCallback(null, result);
}
// ...
tasks.push(function(asyncCallback) { // the _callback here overrides the one above for this closure
console.log('Getting some data');
myCallback(null, result, asyncCallback);
});
// ... more tasks
async wants its callback to be called so it knows when to continue, but that doesn't mean you can't intercept it with your own handlers :P.
You don't need the function call to _callback. You could simplify it like this.
var async = require("async");
function doSomeLogic(item, callback) {
console.log(item);
callback(null, item + 2);
}
function tasks() {
console.log('Start executing tasks');
var tasks = [];
var result = {};
tasks.push(function(callback){
// do some more stuff ...
callback(null, 'one');
});
tasks.push(function(callback){
// do some more stuff ...
callback(null, 'two');
});
async.series(tasks, function(error, results) {
if (error) {
console.log(error);
}
console.log(results);
console.log('All done');
});
}
tasks();

How do I pass a variable into mongodb callback?

I'm trying to select the distinct values for two fields from my mongodb. Using async.series, I have the following:
function getSettings(target){
var versions = [];
var result = {};
function putResults(key, val){
result[key] = val;
}
async.series(
[
function(callback){
db.get(target).distinct('version', function(err, arr){
if(err) return err;
versions = arr;
callback();
}); //end db call
},
function(callback){
var items;
for(var i = 0; i<versions.length; i++)
{
db.get(target).distinct('instance', {version: versions[i]}, function(err, arr){
items = arr;
putResults(versions[i], items);
}); //end db call
}
}
],
function(err){
if(err) return err;
console.log(result);
}); //end async
}
With this code, I get an "undefined" exception on putResults(versions[i], items). I know it's because versions is out of scope. My question is: how do I get it in scope?
Expected result:
result = {1: [1, 2, 3], 2: [1, 2, 3, 4]}
In our case better use waterfall instead of series, and map, like this
function getSettings(target){
async.waterfall([
function (callback) {
db.get(target).distinct('version', function (err, versions) {
callback(err, versions);
});
},
function (versions, callback) {
async.map(versions, function (version, next) {
db.get(target).distinct('instance', {version: version}, function (err, items) {
var result = {};
result[version] = items;
next(err, result);
});
}, function (err, res) {
callback(err, res);
});
}
], function (err, result) {
if (err) {
return;
}
console.log(result);
});
}
As Alexander mentioned in his comment, if you want to pass the values from the first function to the next one, you should use waterfall instead of series.
As specified in the official documentation regarding waterfall:
Runs the tasks array of functions in series, each passing
their results to the next in the array. However, if any of the tasks
pass an error to their own callback, the next function is not
executed, and the main callback is immediately called with the error.
If you would like to read more about the various capabilities of async I strongly recommend their official documentation (LINK).

Resources