Closures & async node.js functions - javascript

All,
Trying to get my head around closures in a node.js context (async calls).
I have the following code:
timer = setInterval(pollOID, 1000);
function pollOID() {
for (channel in channels) {
session.get({ oid: channels[channel].oid }, function (varbinds) {
console.log("The " + channels[channel].name + " is " + varbinds);
});
}
}
The code polls a router for SNMP data each second using a loop in the setInterval callback to query the router for several SNMP entities. The session.get function has an async callback to process the results from the router.
The SNMP bits are working fine, my question is about how to persist the value of the loop variable channel inside the session async callback.
I get the following results:
The Download Attenuation is 7.5
The Download Attenuation is 361600
The Download Attenuation is 60
So the loop variable channel is changing for each call to session.get as the function is returning the correct value from the router. My problem is that channels[channel].name uses the current value of channel which by the time the callback has returned the loop has ended and channel is 2 (the third loop, which is the name string "download attenuation"). So I need to persist the value of channel inside the session.get callback to the value it was when the callback is called so the correct channels[channel].name is used in the session.get callback.
I know I have to use a closure for this but after trying a number of different approaches I can't get it working properly. Any clues to point me in the right direction? Thanks!

You can create a simple closure to hold on to a local copy of channel.
function pollOID() {
for (channel in channels) {
(function(channel){
session.get({ oid: channels[channel].oid }, function (varbinds) {
console.log("The " + channels[channel].name + " is " + varbinds);
});
})(channel);
}
Or you can also use bind to pass in the argument, but the context will change inside the callback though.
for (channel in channels) {
session.get({ oid: channels[channel].oid }, (function (channel, varbinds) {
console.log("The " + channels[channel].name + " is " + varbinds);
}).bind(this, channel));
}
And as you guessed your issue is due to accessing channel in the callback which is a shared variable and by the time the callback is invoked your for loop would have run through and channel will be holding the last key enumerated from channels.

Another method is to use async module, and this simplifies control flow which can improve readability as more async calls are introduced.
function pollOID() {
for (channel in channels) {
(function(channel){
session.get({ oid: channels[channel].oid }, function (varbinds) {
console.log("The " + channels[channel].name + " is " + varbinds);
});
})(channel);
}
becomes
function pollOID() {
var log = function(channel, cb){
session.get({ oid: channel.oid }, function (varbinds) {
console.log("The " + channel.name + " is " + varbinds);
cb(); // Moves onto next element in channels when cb is called
});
};
var allDone = function(err, result) {
// all tasks are complete
};
async.each(channels, log, allDone);
}
async.each will run in parallel so if it needs to be in order, use async.eachSeries instead.

Related

onload in for loop returning only the last item (JS) [duplicate]

Hi I'm using a for each loop to in nodejs script to write multiple files to a local location.For the courseTitleArray I'm using "Biology 101,ruby" and I can write one file successfully but not the both.Please help me out.
Here is my code so far
for (var value in CourseTitleArray) {
console.log( "Course Title " + CourseTitleArray[value]);
var newImageLocation = path.join(__dirname, 'app/img/courseImages', CourseTitleArray[value] + ".png");
fs.readFile(image.path, function(err, data) {
fs.writeFile(newImageLocation, data, function(err) {
console.log(CourseTitleArray[value] + " was created successfully");
});
});
console.log("Loop executed " + value);
}
And in the console I get following logs.
Course Title Biology 101
Loop executed 0
Course Title ruby
Loop executed 1
ruby was created successfully
ruby was created successfully
It seems the loops working fine and as in the log I can see both titles.
But when it's writing "Biology 101,ruby" have executed twice .
Can anybody help me out with this? Thanks
The problem you have is that your callback is called when the loop is finished, so value has changed.
A solution is to use a closure to store the value of value :
for (var value in CourseTitleArray) {
(function(value){
console.log( "Course Title " + CourseTitleArray[value]);
var newImageLocation = path.join(__dirname, 'app/img/courseImages', CourseTitleArray[value] + ".png");
fs.readFile(image.path, function(err, data) {
fs.writeFile(newImageLocation, data, function(err) {
console.log(CourseTitleArray[value] + " was created successfully");
});
});
console.log("Loop executed " + value);
})(value);
}
Note that it's not clear what you mean with your "Loop executed" log : when you log, the writing hasn't yet occurred.

Practise for hell asynchronous function nodeJs

I am working on a student project. My goal is to collect data and store it.
I use nodeJs with express, then I run queries with superagent on ThemoviesDb to collect movies and then store them on neo4j.
Here is my example :
app.get('/', function(req,res){
var hostname = "api.themoviedb.org/3";
var path = "/movie/";
// random id, to store random film
for(i=0;i<39;i++){
randomId = Math.floor(Math.random() * 500) + 80;
console.log(' --------------------- Random id is ---------------------- ' + randomId);
superagent.get(hostname + path + randomId)
.query({ api_key: api_key, append_to_response : 'credits' })
.end((err, res) => {
if (err) {
if(err.status_code = '34') {
return console.log('id : ' + randomId + 'ne correspond pas à un film')
}
else{
return console.log(err);
}
}
cpt ++;
title = res.body.original_title;
if(title){ // Test if title isn't nul, undefined, Nan, empty or 0 to add it
console.log('randomId --> ' + res.body.id + '--> ' + title );
if(!Filmadded.includes(film)){
Filmadded.push(film);
}
}
});
}
console.log('cpt : ' + cpt + '/39');
res.send('it works' + i );
});
I I'm just executing a loop ( 39 because the limit of the api is 40 )
and for each I make a request to get a movie.
The result :
As you can see i first have all the id's displayed then the titles that match the id.
--> I would like to wait until the request is over to move on.
I looked promised but I do not have everything.
I then think that my problem on id / film is due to this.
Thank you for your help and sorry for my english
Your superagent() call is asynchronous. As such, it does not block and your for loop just runs to completion starting all 39 superagent() calls in parallel. You could probably code to run all these in parallel (if the target host allows it), but since you asked for the ability to run them one after another, here's an implementation of your function using the promise capabilities of superagent() and await to serialize the async call inside your for loop so it runs one, waits for it to finish, then runs the next one:
app.get('/', async function(req, res){
let hostname = "api.themoviedb.org/3";
let path = "/movie/";
// random id, to store random film
for (let i = 0; i < 39; i++) {
let randomId = Math.floor(Math.random() * 500) + 80;
console.log(' --------------------- Random id is ---------------------- ' + randomId);
try {
let result = await superagent.get(hostname + path + randomId)
.query({ api_key: api_key, append_to_response : 'credits' });
cpt ++;
let title = result.body.original_title;
if (title) { // Test if title isn't nul, undefined, Nan, empty or 0 to add it
console.log('randomId --> ' + res.body.id + '--> ' + title );
if (!Filmadded.includes(film)) {
Filmadded.push(film);
}
}
} catch(err) {
if(err.status_code = '34') {
console.log('id : ' + randomId + 'ne correspond pas à un film')
}
else{
console.log(err);
}
}
console.log('cpt : ' + cpt + '/39');
}
res.send('it works' + i );
});
In addition, you need to make sure you're declaring all variables you are using so they are accidental globals that can conflict when there are other requests also running.
Other things that don't look correct about this code, but I don't know what you intend:
The variable cpt looks like it needs to be initialized and declared somewhere.
The variable Filmadded probably needs to be scoped locally (not some higher scoped variable that can conflict when multiple requests are running on your server).
It isn't clear what you actually intend to do for error handling here when a superagent() call fails. Here it just logs errors, but you probably need to be able to return an error status if you're getting errors.
As you said, superagent's get function is async, meaning that the event loop doesn't wait for the function to finish before executing the next command. So the loop initiates 40 executions of your loop, which includes creating a random id and then using superagent with that id. So we're talking about two actions - one is synchronous and the second is asynchronous.
Let's look at it in another way. Say we had the following loop:
for(i=0; i<39; i++) {
const randomId = Math.floor(Math.random() * 500) + 80;
console.log("RANDOM IS: ", randomId);
setTimeout(function(){
console.log("PRINT AGAIN: ", randomId);
}, 10000);
}
What you'll have here, is 40 rows of "RANDOM IS: [random_number]" in a consecutive manner, and only after 10 seconds you'll have 40 rows of "PRINT AGAIN: [random_number]", and that's because you set a timeout of 10 seconds for the second logging.
You can compare that setTimeout with 10 seconds to an async function - only in an async function you can't really tell when the function will finish. So basically what you have is similar to the above example - 40 loggings of the random number, and some random-timed promises executions.
So what you might want to consider is promise chaining using the reduce function of js Array, or use es6 async await function notation.
You can use superagent functions as promises, and use then and catch instead. Then, chaining the promises means you wait for one promise to finish and only then executing the following one.

Node & MySQL - connection.query inside connection.query - Object property not accessible

I got a pretty awkward problem.
I create a pool, connect to the database, create a connection and query, get the results, do a bunch of stuff, then I have to create another connection and query, but actually it has to be dynamically so I loop over my Array teacherHours containing the data.
Then more Code is happening, and I have to create an extra loop, because certain elements of my teacherHours Array have to try multiple times to get the correct response from the upcoming query.
So another loop follows, which is supposed to loop as long as availableHours > 0. Now, here is where it all goes left.
A buch of code happens inside the second loop, I prepare my second query, call connection.query() and inside of the callback function I prepare my third query (after doing some other stuff) and this is actually where Node kicks me out.
It gives me TypeError: Cannot read property 'tid' of undefined. tid needs to be accessed for my third query, so I try to access it just like I did before but Node doesn't allow it.
I know that the queries return useful data (rows) so it can't be a problem of querying but receiving no data. Actually I console.log("the rowRIDS"+rowRIDS); the result of the second query and I see that it returns 2 rows and just after that it gives me the error.
What is also strange to me, all the console.logs inside my my two loops are being logged, and my console.log of the second query (containing the 2 rows) are being logged after the loops ran through, since the queries are nested shouldn't the returned 2 rows and the error appear within the first iteration of the loop, since the code should access the second query at that point.
BTW, I've tried to set a hardcoded number instead of the tid just to get the next property datum to be an error. I kind of got a feeling as if the variable teacherHours is out of scope, but it is supposed to be a global variable.
To get a better feeling of what I'm talking about I copied the code and uncommented all the javascript code, where I populate and calculate stuff. Any help would be really great, its been almost 7 hours of try & error without any luck. Thank You!
pool.getConnection(function(err, connection){
if (err) throw err;
connection.query('SELECT * FROM teachers_teaching_tbl WHERE fwdid = 1 ', function(err, rows, fields) {
if (err) {
console.error('error querying: ' + err.stack);
return;
}
rowArray=rows;
console.log(rowArray);
//
// HERE HAPPENS
// A LOOOOT OF STUFF
//
// AND teacherHours IS BEING POPULATED
//
// THEN COMES A FOR LOOP
for(var i=0; i<teacherHours.length;i++){
//
// MORE STUFF
//
//AND ANOTHER LOOP
while(availableHours>0){//do{ ORIGINALLY I TRIED WITH A DO WHILE LOOP
//
// AGAIN A BUNCH OF STUFF
//
// NOW I'M PREPARING MY NEXT QUERY
//
var myQueryGetFreeRoom=" SELECT rms.rid FROM rooms_tbl as rms WHERE NOT EXISTS ( ";
myQueryGetFreeRoom+=" SELECT NULL FROM classes_tbl as cls ";
myQueryGetFreeRoom+=" WHERE ( (cls.bis > '"+bisMinus1+"' AND cls.bis <= '"+realBis+"' ) OR ( cls.von > '"+bisMinus1+"' AND cls.von < '"+realBis+"' ) ) AND (cls.datum = '"+teacherHours[i].datum.getFullYear()+"-"+(teacherHours[i].datum.getMonth()+1)+"-"+teacherHours[i].datum.getDate()+"') AND (cls.rid=rms.rid) ) ";
//
//
connection.query(myQueryGetFreeRoom, function(err, rowRIDS, fields) {
if (err) {
console.error('error querying: ' + err.stack);
return;
}
roomIDs=rowRIDS;
console.log("the rowRIDS"+rowRIDS);
//
// MORE STUFF
// HAPPENING
//
if(roomIDs.length>0){
//
// PREPARING QUERY NO.3 - WHICH IS WHERE MY ERROR POINTS - TO THE USE OF tid PROPERTY
//
var myQueryBookClass = " INSERT INTO classes_tbl ( rid , tid , belegtAnz, datum, von , bis ) ";
myQueryBookClass+=" VALUES ( "+Math.floor(Math.random() * roomIDs.length)+", "+teacherHours[i].tid+" , 0, '"+teacherHours[i].datum.getFullYear()+"-"+(teacherHours[i].datum.getMonth()+1)+"-"+teacherHours[i].datum.getDate()+"' , '"+bisMinus1+"' , '"+realBis+"' ) ";
console.log("myQueryBookClass: "+myQueryBookClass);
availableHours = 0;
//
// HERE WAS SUPPOSED TO FOLLOW QUERY 3 - myQueryBookClass
//
// BUT SINCE I DONT EVEN GET INSIDE HERE IT IS IN COMMENTS
//
/*connection.query(myQueryBookClass, function(err, insertRows, fields){
if(err){
console.error('error querying: '+err.stack);
return;
}
console.log("Inserted Rows: "+ insertRows);
}); */
} else {
availableHours= availableHours - 1;
//
// STUFF HAPPENING
//
}
});
availableHours= availableHours - 1;
}//while(availableHours>0);
//
}
connection.release(function(err){
if (err){
console.error('error disconnecting: ' + err.stack);
return;
}
});
});
});
I think you are coming from a non-async language like Python, Java, etc. which is why Node, i.e. JavaScript, seems to screw things up for you, but actually it isn't.
The problem you have in your code is that you execute async functions like query synchronously all at the same time in the same while loop. You need to use a module like async which helps to run and collect results asynchronously.
Here is the updated code.
var async = require('async'),
connection;
async.waterfall([
function (cb) {
pool.getConnection(cb);
},
function (conn, cb) {
connection = conn;
connection.query('SELECT * FROM teachers_teaching_tbl WHERE fwdid = 1', cb);
},
function (rows, fields, cb) {
rowArray = rows;
console.log(rowArray);
// HERE HAPPENS
// A LOOOOT OF STUFF
//
// AND teacherHours IS BEING POPULATED
//
// THEN COMES A FOR LOOP
async.eachSeries(teacherHours, function (teacherHour, done) {
// MORE STUFF
//
//AND ANOTHER LOOP
async.whilst(function () {
return availableHours > 0;
}, function (cb) {
// AGAIN A BUNCH OF STUFF
//
// NOW I'M PREPARING MY NEXT QUERY
//
var myQueryGetFreeRoom =
"SELECT rms.rid FROM rooms_tbl AS rms WHERE NOT EXISTS ("
+ "SELECT NULL FROM classes_tbl AS cls"
+ " WHERE ("
+ "(cls.bis > '" + bisMinus1 + "' AND cls.bis <= '" + realBis + "')"
+ " OR (cls.von > '" + bisMinus1 + "' AND cls.von < '" + realBis + "')"
+ ") AND ("
+ "cls.datum = '" + teacherHour.datum.getFullYear() + "-" + (teacherHour.datum.getMonth() + 1) + "-" + teacherHour.datum.getDate() + "'"
+ ") AND cls.rid = rms.rid";
async.waterfall([
function (cb) {
connection.query(myQueryGetFreeRoom, cb);
},
function(rowRIDS, fields, cb) {
roomIDs = rowRIDS;
console.log("the rowRIDS" + rowRIDS);
//
// MORE STUFF
// HAPPENING
//
if (roomIDs.length > 0) {
//
// PREPARING QUERY NO.3 - WHICH IS WHERE MY ERROR POINTS - TO THE USE OF tid PROPERTY
//
var myQueryBookClass = "INSERT INTO classes_tbl (rid, tid, belegtAnz, datum, von, bis) VALUES ("
+ Math.floor(Math.random() * roomIDs.length)
+ ", " + teacherHour.tid
+ ", 0, '" + teacherHour.datum.getFullYear() + "-" + (teacherHour.datum.getMonth() + 1) + "-" + teacherHour.datum.getDate() + "', '" + bisMinus1 + "', '" + realBis + "')";
console.log("myQueryBookClass: " + myQueryBookClass);
availableHours = 0;
//
// HERE WAS SUPPOSED TO FOLLOW QUERY 3 - myQueryBookClass
//
// BUT SINCE I DONT EVEN GET INSIDE HERE IT IS IN COMMENTS
//
connection.query(myQueryBookClass, function (err, insertRows, fields) {
if (err) {
console.error('error querying: '+err.stack);
return;
}
console.log("Inserted Rows: "+ insertRows);
// Here do whatever you need to do, then call the callback;
cb();
});
} else {
--availableHours;
//
// STUFF HAPPENING
//
cb();
}
}
], function (err) {
if (!err) {
// Notice that you are decrementing the `availableHours` twice here and above.
// Make sure this is what you want.
--availableHours;
}
cb(err);
});
}, done);
}, function (err) {
connection.release(function (err) {
if (err) {
console.error('error disconnecting: ' + err.stack);
return;
}
});
});
}
], function (err) {
conn && pool.release(conn);
err && throw err;
});
Next time please format your code properly for better readability which will help yourself to get answers faster, and split your question text into paragraphs for the same purpose.
Explanation
There are four nested async flows:
async.waterfall
-> async.eachSeries
-> async.whilst
-> async.waterfall
Basically, the async.waterfall library allows you to execute a list of functions in series.
Every next function will be executed only after the previous function has returned the response.
To indicate that a function is completed and the results are available, it has to call the callback, in our case it is cb (you can call it whatever you like, eg. callback). The rule is to call it, otherwise, the next function will never be executed because the previous one doesn't seem to have finished its work.
Once the previous function has completed, it calls the provided cb with the following signature:
cb(err, connection);
If there was an error while requesting for a connection, the entire async.waterfall will interrupt and the final callback function will be executed.
If there was no error, the connection will be provided as a second argument. async module passes all arguments of the previous function to the next function as the first, second, etc. arguments which is why the second function receives the conn as the first argument.
Every next function will receive the callback cb as the last argument, which you must eventually call when the job is done.
Thus, in the first async.waterfall flow:
It requests a new database connection.
Once the connection is available, the next function is executed which sends a query to the database.
Waits for the query results, then once the results are available, it is ready to run the next function which iterates over each row.
async.eachSeries allows to iterate over a gives array of values sequentially.
In the second async.eachSeries flow:
It iterates over each element in the teacherHours array sequentially.
Once each element is processed (however you want), you must call the done callback. Again, you could have called this as cb like in the previous async.waterfall or callback. done is just for clarity that the process is done.
Then we have the async.whilst which provides the same logic as the normal while () {} statement but handles the loop asynchronously.
In this third async.whilst flow:
Calls the first function. Its return value indicates whether it has to continue the loop, i.e. call the second asynchronous function.
If the return value is truthful (availableHours > 0), then the second function is called.
When the async function is done, it must call the provided callback cb to indicate that it is over. Then async module will call the first function to check if it has to continue the loop.
In this asynchronous function inside async.whilst we have another async.waterfall because you need to send queries to the database for each teacherHour.
In this last fourth async.watercall flow:
It sends the SELECT query to the database.
Waits for the response. Once the rowRIDS are available, it calls the second function in the waterfall.
If there are rowRIDS (roomIDs.length > 0), it sends the INSERT query to the database.
Once done, it calls the callback cb.
If there were no rowRIDs, it calls the callback cb, too, to indicate that the job is done.
It is a great thing that JavaScript is asynchronous. It might be difficult at the beginning when you convert from other synchronous languages, but once you get the idea, it will be hard to thing synchronously. It becomes so intuitive that you will start thinking why other languages don't work asynchronous.
I hope I could explain the above code thoroughly. Enjoy JavaScript! It's awesome!

child process spawn returning NaN

I'm trying to understand child process module in node.js, I created a parent file which has code:
var spawn=require("child_process").spawn;
var child=spawn("node",['plus_one.js']);
setInterval(function(){
//var number=Math.floor(Math.random()*10000);
var number=10;
child.stdin.write(number + "\n");
child.stdout.once("data",function(data){
console.log("Child replied to "+number + " with " + data);
})
},1000);
child.stderr.on("data",function(data){
//process.stdout.write(data);
console.log("error"+data)
})
The child file looks like this:
process.stdin.resume();
process.stdin.on("data",function(data){
var number;
try{
number = parseInt(data.toString(), 10);
number+=1;
process.stdout.write(number+"\n");
}
catch(err){
process.stderr.write(err.message+"lol");
}
})
If I execute just the child file it works fine , but when i execute the main file it always return NaN; why is that?
Also as im trying to understand it, I quite do not understand the difference between child_process.spawn and .exec, spawn return stream so it has stdin/stdout while exec returns buffer, does it mean that .exec cannot communicate with child file (and vice versa) other than passing variable with options/env object in it?
Making a few tweaks to your code, it is now working for me:
var spawn = require("child_process").spawn;
var child = spawn("node", ['plus_one.js']);
var number = 10;
setInterval(function () {
child.stdin.write(number++ + "\n");
child.stdout.once("data", function (data) {
console.log("Child replied to " + number + " with " + data);
});
}, 1000);
child.stderr.on("data", function (data) {
//process.stdout.write(data);
console.log("error" + data)
});
Changes:
Used proper bracing on the setInterval() function.
Used .once() in the appropriate place so event handlers don't pile up.
Moved the number variable outside of the setInterval() scope so that it can retain its value from one call to the next.

JavaScript Callbacks and Splunk

I am in the process of using the Splunk Javascript API to gain access to some of its functionality, but I'm having trouble understanding JavaScript concepts behind callbacks.
An example from the docs:
var http = new splunkjs.ProxyHttp("/proxy");
var service = new splunkjs.Service(http, {
username: username,
password: password,
scheme: scheme,
host: host,
port: port,
version: version
});
Async.chain([
// First, we log in
function(done) {
service.login(done);
},
// Perform the search
function(success, done) {
if (!success) {
done("Error logging in");
}
service.search("search index=_internal | head 3", {}, done);
},
// Wait until the job is done
function(job, done) {
Async.whilst(
// Loop until it is done
function() { return !job.properties().isDone; },
// Refresh the job on every iteration, but sleep for 1 second
function(iterationDone) {
Async.sleep(1000, function() {
// Refresh the job and note how many events we've looked at so far
job.fetch(function(err) {
console.log("-- fetching, " + (job.properties().eventCount || 0) + " events so far");
iterationDone();
});
});
},
// When we're done, just pass the job forward
function(err) {
console.log("-- job done --");
done(err, job);
}
);
},
// Print out the statistics and get the results
function(job, done) {
// Print out the statics
console.log("Job Statistics: ");
console.log(" Event Count: " + job.properties().eventCount);
console.log(" Disk Usage: " + job.properties().diskUsage + " bytes");
console.log(" Priority: " + job.properties().priority);
// Ask the server for the results
job.results({}, done);
},
// Print the raw results out
function(results, job, done) {
// Find the index of the fields we want
var rawIndex = utils.indexOf(results.fields, "_raw");
var sourcetypeIndex = utils.indexOf(results.fields, "sourcetype");
var userIndex = utils.indexOf(results.fields, "user");
// Print out each result and the key-value pairs we want
console.log("Results: ");
for(var i = 0; i < results.rows.length; i++) {
console.log(" Result " + i + ": ");
console.log(" sourcetype: " + results.rows[i][sourcetypeIndex]);
console.log(" user: " + results.rows[i][userIndex]);
console.log(" _raw: " + results.rows[i][rawIndex]);
}
// Once we're done, cancel the job.
job.cancel(done);
}
],
function(err) {
callback(err);
}
);
Async.chain is defined here as being root.chain = function(tasks, callback). My understanding is that there are 5 functions in the tasks array which are executed one after the other, and pass the results from one to the other.
However I do not understand how and where "done", "success","job" and "results" are defined, or how it is that they are used as arguments within the body of their functions?
function(success, done) {
if (!success) {
done("Error logging in");
}
service.search("search index=_internal | head 3", {}, done);
}
here, how is it testing against success, and passing a string to done()?
and how does the two functions
function(job, done) {// Print out the statics ..}
&
function(results, job, done) { .. }
pass the results data from the first function to the second?
Apologies for the long question.
In Javascript, functions create new scope. That means it does not matter what the passed arguments were named before they were passed to the function.
var awesomeName = 'bob';
hi(awesomeName);
// name === undefined
function hi(name) {
// name === 'bob';
console.log('hi', name); // Outputs: 'hi bob' in console
}
// name === undefined
As you said, each task calls the next task as a callback. The last argument is always the next task function/callback. That means that Async.chain probably automagically adds the callbacks to the end of the arguments before calling each task function. done is just a conventional name to assign to the callback. Similarly, the other arguments are just descriptive names for the arguments passed by the previous task. In order to see why they are named that way, you should look at the function that is calling the callback.
For example:
service.login(done) probably has some kind of code in it that does something like this:
login: function(callback) {
var successful;
// Do Login logic here and assign true/false to successful
callback(successful);
}
The callback is the next task in the chain and has two arguments, success and done. success is just the first argument that login passed to it. Async.chain always passes another argument as the last argument: the next task function, which is just assigned the name done by convention. You could name it whatever you want within each function, as long as you refer to it as the same name within the function.
function cb(success, fuzzyCallback) {
if (!success) {
fuzzyCallback('Error!');
}
fuzzyCallback(null);
}

Categories

Resources