RangeError: call stack exceeds async.eachSeries
Finally, the actual error is listed on stackoverflow!
The code below shows the following error:
var m = pathA.substr(-(pathB.length)); // var
^
RangeError: Maximum call stack size exceeded
I'm sure the answer is reported here at the bottom:
https://github.com/caolan/async/issues/75
However, I don't understand how to fix my code. As far as I know, I am not calling sync functions inside async functions. Can anyone elaborate on what I need to do to fix my code?
I am iterating across the cross product of the result set to concatenate path strings where one is a substring of the other.
var i = 0;
async.eachSeries(results.rows, function (r, next2a) {
var pathA = results.rows[i].id_path;
var j = 0;
async.eachSeries(results.rows, function (r2, next1a) {
var pathB = results.rows[j].id_path;
//check i=j
if (!(i == j)) {
var m = pathA.substr(-(pathB.length)); // var m = (pathA || '').substr(-((pathB) ? pathB.length : 0));
if ((m == pathB) && (pathA.length > pathB.length)) {
logger.log('DEBUG', (pathB + ' => ' + pathA));
conn.query("UPDATE user_token_details SET id_l1=$1, id_l2=$2, id_l3=$3, id_l4=$4,id_l5=$5,id_path2=$9, id_path=$6 WHERE token_uuid=$7 AND user_uuid=$8",
[results.rows[i].id_l1, results.rows[i].id_l2, results.rows[i].id_l3, results.rows[i].id_l4, results.rows[i].id_l5, results.rows[i].id_path,
results.rows[j].token_uuid, user_uuid, results.rows[j].id_path],
function (error, result) {
if (error) {
throw error;
}
j++;
next1a();
})
} else {
j++;
next1a();
}
} else {
j++;
next1a();
}
}, function () {
i++;
next2a();
});
}, function (err) {
});
Here is the shape of these spaghetti:
var A = [0, 1, 2, 3, 4...300];
async.eachSeries(A, function (a, next_a) {
async.eachSeries(A, function (b, next_b) {
// "Range Error: Maximum call stack size exceeded"
doSomethingAsync(a,b, function () {
next_a();
});
}, function (err) {
next_b();
})
}, function (err) {
// resume
})
source to share
The problem is that it async.eachSeries
behaves asynchronously if the callback inside it is called asynchronously. In your case, your last two calls next1a
do not fulfill the request, so they happen synchronously and thus expand the call stack. In this case, you are probably iterating enough so that you get the maximum stack depth. The simplest solution is to always call asynchronously next1a
.
Replace every instance
next1a();
from
setImmediate(next1a);
except for the one that is already asynchronous due to the request. Note that while it process.nextTick(next1a)
will also work, it can block the event loop from processing any other tasks. This is because it process.nextTick
queues the callback as microtask
, whereas it setImmediate
calls the callback as macrotask
.
source to share