Don't understand the inner callback in async.parallel() - javascript

I need help understanding async.parallel(tasks, callback).
From what I understand, the list of tasks are executed, and once they're finished, all the results are then passed to callback.
An example of it in action is:
async.parallel([
function(callback) {
setTimeout(function() {
console.log('Task One');
callback(null, 1); <----- DON'T UNDERSTAND
}, 200);
},
function(callback) {
setTimeout(function() {
console.log('Task Two');
callback(null, 2); <----- DON'T UNDERSTAND
}, 100);
}
],
function(err, results) {
console.log(results);
// the results array will equal [1, 2] even though
// the second function had a shorter timeout.
});
The part that I don't understand however, are the inner calls to callback. Specifically, what does it mean when we call callback(null, 1) and callback(null, 2)? What do the null and the 1 or 2 refer to?

Related

Executing multiple HTTP requests sequentially using async.js

How can I execute multiple HTTP requests sequentially using async.js . I checked the async.js documentation but couldn't figure out, how to do that. I want to achieve the same thing as below code using async.js callback style.
var http = require('http');
var Q = require('q');
var URL="http://localhost:3000";
var getPromise=function(url) {
var deferred = Q.defer();
var req = http.get(url, function(response) {
if(response.statusCode < 200 || response.statusCode > 299){
deferred.reject(new Error('ErrorCode '+response.statusCode))
}
var result="";
response.on('data',function(chunk){result +=chunk;} )
response.on('end',function(){deferred.resolve(result);} )
});
req.on('error',function(err){
console.error('Error with the request:', err.message);
deferred.reject(err);
});
req.end();
return deferred.promise;
}
getPromise('http://localhost:3000/olympic/2016/ranking/4')
.then(function(data){
console.log("Response 1 "+data)
return getPromise(URL+'/iso/country/'+JSON.parse(data).Country);
})
.then(function(data){
console.log("Response 2 "+data)
return getPromise(URL+'/olympic/2016/medal/'+JSON.parse(data).iso);
})
.then(function(data){
console.log("Response 3 "+data)
})
.catch(function(err){
console.log(err)
});
I got it, I needed async.waterfall it takes an array of functions and execute them one by one. Also we can pass result from previous function execution to the next one
var async = require('async');
async.waterfall([
function task1(done) {
console.log('start!');
setTimeout(function(){
console.log("T1 Complete");
// <- set value to passed to step 2
done(null, 'Value from step 1');
},5000);
},
function task2(task1Result, done) {
console.log(task1Result);
setTimeout(function(){
console.log("T2 Complete");
// <- set value to passed to step 3
done(null, 'Value from step 2');
},1000);
},
function task3 (task2Result, done) {
console.log(task2Result);
setTimeout(function(){
console.log("T3 Complete");
// <- no value set for the next step.
done(null);
},100);
}
],
function (err) {
if (err) {
throw new Error(err);
} else {
console.log('No error happened in any steps, operation done!');
}
});
Looking over the code a bit and trying to understand it more, I believe that async.waterfall is the function you'll need. What this will do is run each function in order, passing its results to the next function in the sequence. Here's an example:
async.waterfall([
function(callback)
{
// Function 1: do request here...
callback(null, val); // replace null with a value if you want the waterfall to error and go straight to the end
},
function(val, callback) {
// Function 2: do your second request here
callback(null, val1, val2, val3); // you can pass any number of variables you like, just make sure the next function in the sequence expects them
},
function(val1, val2, val3, callback)
{
// Function 3: do your third request here
callback(null, result);
} // this can go on for as long as you like
], function(err, result)
{
// this will be called immediately if the first parameter in any of the callbacks is not null, or when all the functions have run
});

Use Async module with parallel function in Node.js

I'm working with socials API and I need to be able to run those function that return the json from the socials API endpoint in parallel, in a way that only when those function are all finished I can work on their data together.
I'm trying to work with ASync module for npm but I'm not able to understand how to make it works.
Looking at the documentation I've seen this so far:
async.parallel([
function(){ ... },
function(){ ... }
], callback);
The problems is that I didn't understand how can I use it.
I would like to do something like this below, but without timeout and with my async functions ( these function returns me the response from the APIs ).
async.series([
function(callback) {
setTimeout(function() {
console.log(“Task 1”);
callback(null, 1);
}, 300);
},
function(callback) {
setTimeout(function() {
console.log(“Task 2”);
callback(null, 2);
}, 200);
},
function(callback) {
setTimeout(function() {
console.log(“Task 3”);
callback(null, 3);
}, 100);
}
], function(error, results) {
console.log(results);
});
Cuold you please help me ?

node.js async.each() callback was called before all iteration was finished

Can somebody explain me how I can to do callback only after all iteration was finished? I used async.each function for that:
async.each(products, function (product, callback) {
fs.appendFile('ParseLog.txt', "PRODUCT name: " + product.name, function (err) {
console.log("iterate");
callback();
});
}, function (err) {
console.log("ALL FINISH");
});
So my input looks like:
ALL FINISH
iterate
iterate
iterate
...
but I expect that "ALL FINISH" message will prints AFTER all iteration.
EDIT 1:
Sorry but it seems trouble was in if(i > 10) return callback({ data: 'hi'}); // stop at start of each loop.
I just want to exit after 11 iteration, but it stranges to me why its do callback at first.?
async.each(products, function (product, callback) {
var i = products.indexOf(product);
if(i > 10) return callback({ data: 'hi'}); // stop
fs.appendFile('ParseLog.txt', "PRODUCT name: " + product.name, function (err) {
console.log("iterate");
callback();
});
..
You should limit the number of products to process before you pass it into async.each:
async.each(products.slice(0, 11), function (product, callback) {
fs.appendFile('ParseLog.txt', "PRODUCT name: " + product.name, function (err) {
console.log("iterate");
callback(err); // make sure to pass `err`!
});
}, function(err) {
if (err) console.log('ERROR', err);
console.log("ALL FINISH");
});
Also, when you call a continuation callback, the first argument is "reserved" to signal that an error occurred. In your example, you're using it to pass an object ({ data: 'hi' }) which will make async think that an error happened (unless that was your intention?). The proper idiom is this:
callback(null, { data: 'hi' })

how to understand callbacks and async.parallel in node

I'm very new to JavaScript and callbacks, so my apologies if this is a stupid question. Based on the async docs for parallel, I came up with this example code that executed the expected way based on the docs:
async = require('async')
async.parallel([
function(callback){
setTimeout(function(){
callback(null, 'one');
}, 800);
},
function(callback){
setTimeout(function(){
callback(null, 'two');
}, 100);
}
],
function(err, results){
console.log(results)
})
Running this with node foo.js prints a results array ['one', 'two'] as the docs indicate it will. The thing I don't understand is how exactly this works: when you pass callback as a parameter to each function and then callback is called as callback(null, res), what exactly is being called her? I've not actually defined any function callback, nor have I passed any sort of operating callback function as a parameter, yet everything magically works fine. Am I totally missing the point here? Or is this actually the under-the-hood magic of async?
You are not the one passing callback to the task functions, the async module is. It's a special function that the module passes to your task functions that when called, checks if any more tasks are left.
Here is something similar to what is being done inside async:
function myParallel(tasks, finalcb) {
var tasksLeft = tasks.length,
results = [],
ignore = false;
function callback(err, result) {
if (ignore) return;
if (err) {
ignore = true;
finalcb && finalcb(err);
} else if (--tasksLeft === 0) {
ignore = true;
finalcb && finalcb(null, results);
} else
results.push(result);
}
tasks.forEach(function(taskfn) {
taskfn(callback);
});
}
myParallel([
function(callback) {
setTimeout(function() {
callback(null, 'one');
}, 800);
},
function(callback) {
setTimeout(function() {
callback(null, 'two');
}, 100);
}
], function(err, results){
console.log(results)
});

node.js async.series is that how it is supposed to work?

var async = require('async');
function callbackhandler(err, results) {
console.log('It came back with this ' + results);
}
function takes5Seconds(callback) {
console.log('Starting 5 second task');
setTimeout( function() {
console.log('Just finshed 5 seconds');
callback(null, 'five');
}, 5000);
}
function takes2Seconds(callback) {
console.log('Starting 2 second task');
setTimeout( function() {
console.log('Just finshed 2 seconds');
callback(null, 'two');
}, 2000);
}
async.series([takes2Seconds(callbackhandler),
takes5Seconds(callbackhandler)], function(err, results){
console.log('Result of the whole run is ' + results);
})
The output looks like below :
Starting 2 second task
Starting 5 second task
Just finshed 2 seconds
It came back with this two
Just finshed 5 seconds
It came back with this five
I was expecting the takes2Second function to finish completely before the takes5Second starts.
Is that how it is supposed to work. Please let me know.
And the final function never runs. Thanks.
Not quite. You are executing the functions immediately (as soon as the array is evaluated), which is why they appear to start at the same time.
The callback passed to each of the functions to be executed is internal to the async library. You execute it once your function has completed, passing an error and/or a value. You don't need to define that function yourself.
The final function never runs in your case because the callback function that async needs you to invoke to move on to the next function in the series never actually gets executed (only your callbackHandler function gets executed).
Try this instead:
async.series([
takes2Seconds,
takes5seconds
], function (err, results) {
// Here, results is an array of the value from each function
console.log(results); // outputs: ['two', 'five']
});
James gave you a good overview of async.series. Note that you can setup anonymous functions in the series array and then call your actual functions with parameters
var async = require('async')
var param1 = 'foobar'
function withParams(param1, callback) {
console.log('withParams function called')
console.log(param1)
callback()
}
function withoutParams(callback) {
console.log('withoutParams function called')
callback()
}
async.series([
function(callback) {
withParams(param1, callback)
},
withoutParams
], function(err) {
console.log('all functions complete')
})
My preferred way to create the async series is using operational array as follow;
var async = require('async'),
operations = [];
operations.push(takes2Seconds);
operations.push(takes5seconds);
async.series(operations, function (err, results) {
// results[1]
// results[2]
});
function takes2Seconds(callback) {
callback(null, results);
}
function takes5seconds(callback) {
callback(null, results);
}
async.series
([
function (callback)
{
response=wsCall.post(user,url,method,response);
console.log("one");
callback();
}
,
function (callback)
{
console.log("two");
//console.log(response);
callback();
}
]
,
function(err)
{
console.log('Both a and b are saved now');
console.log(response);
});
In async.series,all the functions are executed in series and the consolidated outputs of each function is passed to the final callback. e.g
var async = require('async');
async.series([
function (callback) {
console.log('First Execute..');
callback(null, 'userPersonalData');
},
function (callback) {
console.log('Second Execute.. ');
callback(null, 'userDependentData');
}
],
function (err, result) {
console.log(result);
});
Output:
First Execute..
Second Execute..
['userPersonalData','userDependentData'] //result

Categories

Resources