Thanks for the stripped-down repro. The error is being thrown because you're invoking a null-valued variable as a function.
When you call asyncTester yourself you provide null for asyncCb, while the function you give to async.series supplies an actual callback function.
I've updated your code and added a few console.log statements to illustrate the point.
var async = require('async');
// number is an integer, deepdive defines if the function is called the
// first time or not, cb contains the regular callback, asynCb contains
// the asyncJS callback
var asyncTester = function(number, deepdive, cb, asyncCb) {
console.log(asyncCb); // <=== new
//check if function should nest itself -- only on the first call
if (deepdive == true) {
var funcArray = [];
//load async with multiple calls of this function
for (var times = 0; times < 4; times++) {
funcArray.push(function(callback) {
asyncTester(times, false, null, callback);
});
}
//call async with array of functions and final callback handling
async.series(funcArray,
function(err, results) {
//return the original callback with the results from
// the async series
console.log('.series callback'); // <=== new
return cb(err, results);
});
}
//return the async callback when in a nested call
return asyncCb(null, number);
};
asyncTester(
1, true,
function(err, data) { console.log(data); },
function() { console.log('all done!'); } // <=== new
);
Output of original with console.log:
null
[Function]
[Function]
[Function]
[Function]
.series callback
[ 4, 4, 4, 4 ]
/Users/pmidge/workspace/personal/jstest/main.js:2079
return asyncCb(null, number);
^
TypeError: asyncCb is not a function
at asyncTester (/Users/pmidge/workspace/personal/jstest/main.js:2079:16)
at test63 (/Users/pmidge/workspace/personal/jstest/main.js:2082:5)
at Object.<anonymous> (/Users/pmidge/workspace/personal/jstest/main.js:2090:1)
at Module._compile (module.js:413:34)
at Object.Module._extensions..js (module.js:422:10)
at Module.load (module.js:357:32)
at Function.Module._load (module.js:314:12)
at Function.Module.runMain (module.js:447:10)
at startup (node.js:139:18)
at node.js:999:3
Output with function instead of null:
[Function]
[Function]
[Function]
[Function]
[Function]
.series callback
[ 4, 4, 4, 4 ]
initiating call done!
I suspect your investigation of this issue was hampered by the fact that everything happens in order since (not sure if this was deliberate) you don't actually do anything asynchronous in this example.
We can force asynchronous execution of your inner code by substituting the following code for the body of the anonymous function you push into the array given to async.series:
setImmediate(function() {
asyncTester(times, false, null, callback);
});
Then the console output looks like this, and it's more obvious that you have a bug in the code that runs immediately instead of in a future iteration of the event loop:
null
/Users/pmidge/workspace/personal/jstest/main.js:2079
return asyncCb(null, number);
^
TypeError: asyncCb is not a function
at asyncTester (/Users/pmidge/workspace/personal/jstest/main.js:2079:16)
at test63 (/Users/pmidge/workspace/personal/jstest/main.js:2082:5)
at Object.<anonymous> (/Users/pmidge/workspace/personal/jstest/main.js:2090:1)
at Module._compile (module.js:413:34)
at Object.Module._extensions..js (module.js:422:10)
at Module.load (module.js:357:32)
at Function.Module._load (module.js:314:12)
at Function.Module.runMain (module.js:447:10)
at startup (node.js:139:18)
at node.js:999:3
If you don't want to provide a callback at all, you can just guard your return statement like this:
//return the async callback when in a nested call
return asyncCb
? asyncCb(null, number)
: null;
asyncTester(...)you are calling that function. By default, functions returnundefined. So in each of those calls, you're returningundefinedinstead of a function.for (var times = 2; times > 0; times--) { funcArray.push(function (callback) { asyncTester(2, false, null, callback); } ); }funcArray.push(function(callback) { asyncTester(2, false, null, callback); })because now you're expecting a new callback to be passed every time you call a function in the array. Just dofuncArray.push(function() { asyncTester(2, false, null, asyncCb); })