summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCaolan McMahon <caolan@caolanmcmahon.com>2013-01-31 14:53:25 +0000
committerCaolan McMahon <caolan@caolanmcmahon.com>2013-01-31 14:53:25 +0000
commit6ad64aca4c04857086f03db7ae8c0fb104e76f95 (patch)
tree1e8702ab815f158c6523785d7e4abf0247d05870
parent48d8cbef98cb6c9c68d6748f0684203a03959135 (diff)
downloadasync-6ad64aca4c04857086f03db7ae8c0fb104e76f95.tar.gz
automatically call nextTick on some synchronous function calls
-rw-r--r--lib/async.js53
-rw-r--r--test/test-async.js42
2 files changed, 90 insertions, 5 deletions
diff --git a/lib/async.js b/lib/async.js
index 0d250ea..71903b3 100644
--- a/lib/async.js
+++ b/lib/async.js
@@ -118,6 +118,7 @@
}
var completed = 0;
var iterate = function () {
+ var sync = true;
iterator(arr[completed], function (err) {
if (err) {
callback(err);
@@ -129,10 +130,16 @@
callback(null);
}
else {
- iterate();
+ if (sync) {
+ async.nextTick(iterate);
+ }
+ else {
+ iterate();
+ }
}
}
});
+ sync = false;
};
iterate();
};
@@ -592,12 +599,21 @@
async.whilst = function (test, iterator, callback) {
if (test()) {
+ var sync = true;
iterator(function (err) {
if (err) {
return callback(err);
}
- async.whilst(test, iterator, callback);
+ if (sync) {
+ async.nextTick(function () {
+ async.whilst(test, iterator, callback);
+ });
+ }
+ else {
+ async.whilst(test, iterator, callback);
+ }
});
+ sync = false;
}
else {
callback();
@@ -605,27 +621,45 @@
};
async.doWhilst = function (iterator, test, callback) {
+ var sync = true;
iterator(function (err) {
if (err) {
return callback(err);
}
if (test()) {
- async.doWhilst(iterator, test, callback);
+ if (sync) {
+ async.nextTick(function () {
+ async.doWhilst(iterator, test, callback);
+ });
+ }
+ else {
+ async.doWhilst(iterator, test, callback);
+ }
}
else {
callback();
}
});
+ sync = false;
};
async.until = function (test, iterator, callback) {
if (!test()) {
+ var sync = true;
iterator(function (err) {
if (err) {
return callback(err);
}
- async.until(test, iterator, callback);
+ if (sync) {
+ async.nextTick(function () {
+ async.until(test, iterator, callback);
+ });
+ }
+ else {
+ async.until(test, iterator, callback);
+ }
});
+ sync = false;
}
else {
callback();
@@ -633,17 +667,26 @@
};
async.doUntil = function (iterator, test, callback) {
+ var sync = true;
iterator(function (err) {
if (err) {
return callback(err);
}
if (!test()) {
- async.doUntil(iterator, test, callback);
+ if (sync) {
+ async.nextTick(function () {
+ async.doUntil(iterator, test, callback);
+ });
+ }
+ else {
+ async.doUntil(iterator, test, callback);
+ }
}
else {
callback();
}
});
+ sync = false;
};
async.queue = function (worker, concurrency) {
diff --git a/test/test-async.js b/test/test-async.js
index 6f2b975..e369f0c 100644
--- a/test/test-async.js
+++ b/test/test-async.js
@@ -2026,3 +2026,45 @@ exports['queue events'] = function(test) {
q.push('poo', function () {calls.push('poo cb');});
q.push('moo', function () {calls.push('moo cb');});
};
+
+exports['avoid stack overflows for sync tasks'] = function (test) {
+ var arr = [];
+ var funcarr = [];
+ for (var i = 0; i < 100000; i++) {
+ arr.push[i];
+ funcarr.push(function (cb) { return cb(); });
+ }
+ var iter = function (i, cb) { cb(); };
+ var counter = 0;
+ var pred1 = function () {
+ return counter <= 100000;
+ };
+ var iter = function (cb) {
+ counter++;
+ cb();
+ };
+ var pred2 = function () {
+ return counter > 100000;
+ };
+ var resetCounter = function (cb) {
+ counter = 0;
+ cb();
+ }
+ async.series([
+ async.apply(async.forEach, arr, iter),
+ async.apply(async.forEachSeries, arr, iter),
+ async.apply(async.forEachLimit, arr, iter, 2),
+ async.apply(async.whilst, pred1, iter),
+ resetCounter,
+ async.apply(async.until, pred2, iter),
+ resetCounter,
+ async.apply(async.doWhilst, iter, pred1),
+ resetCounter,
+ async.apply(async.doUntil, iter, pred2),
+ async.apply(async.series, funcarr),
+ async.apply(async.parallel, funcarr)
+ ],
+ function (err) {
+ test.done(err);
+ });
+};