diff options
author | Caolan McMahon <caolan@caolanmcmahon.com> | 2013-01-31 15:12:16 +0000 |
---|---|---|
committer | Caolan McMahon <caolan@caolanmcmahon.com> | 2013-01-31 15:12:16 +0000 |
commit | 418ae9fb8f03a55255571774a5c0db6faac23120 (patch) | |
tree | 21b67b1c0209cec5fe49424a98188d4786429ed6 | |
parent | e4979da603ddd1568fdbf19df640a041b6f392b4 (diff) | |
download | async-418ae9fb8f03a55255571774a5c0db6faac23120.tar.gz |
fix stackoverflows in queue when using synchronous tasks - WARNING, this slightly changes order of events when queue processing using sync tasks
-rw-r--r-- | lib/async.js | 27 | ||||
-rw-r--r-- | test/test-async.js | 21 |
2 files changed, 37 insertions, 11 deletions
diff --git a/lib/async.js b/lib/async.js index 71903b3..7e8d2d0 100644 --- a/lib/async.js +++ b/lib/async.js @@ -706,7 +706,7 @@ data: task, callback: typeof callback === 'function' ? callback : null }); - if (q.saturated && q.tasks.length == concurrency) { + if (q.saturated && q.tasks.length === concurrency) { q.saturated(); } async.nextTick(q.process); @@ -715,16 +715,33 @@ process: function () { if (workers < q.concurrency && q.tasks.length) { var task = q.tasks.shift(); - if(q.empty && q.tasks.length == 0) q.empty(); + if (q.empty && q.tasks.length === 0) { + q.empty(); + } workers += 1; - worker(task.data, only_once(function() { + var sync = true; + var next = function () { workers -= 1; if (task.callback) { task.callback.apply(task, arguments); } - if(q.drain && q.tasks.length + workers == 0) q.drain(); + if (q.drain && q.tasks.length + workers === 0) { + q.drain(); + } q.process(); - })); + }; + var cb = only_once(function () { + if (sync) { + async.nextTick(function () { + next.apply(null, arguments); + }); + } + else { + next.apply(null, arguments); + } + }); + worker(task.data, cb); + sync = false; } }, length: function () { diff --git a/test/test-async.js b/test/test-async.js index da6956a..956165d 100644 --- a/test/test-async.js +++ b/test/test-async.js @@ -2006,17 +2006,17 @@ exports['queue events'] = function(test) { test.same(calls, [ 'saturated', 'process foo', - 'foo cb', 'process bar', - 'bar cb', 'process zoo', - 'zoo cb', + 'foo cb', 'process poo', - 'poo cb', + 'bar cb', 'empty', 'process moo', + 'zoo cb', + 'poo cb', 'moo cb', - 'drain', + 'drain' ]); test.done(); }; @@ -2066,7 +2066,16 @@ exports['avoid stack overflows for sync tasks'] = function (test) { resetCounter, async.apply(async.doUntil, iter, pred2), async.apply(async.series, funcarr), - async.apply(async.parallel, funcarr) + async.apply(async.parallel, funcarr), + function (callback) { + var q = async.queue(function (task, cb) { + cb(); + }, 2); + for (var j = 0; j < 10000; j++) { + q.push(j); + } + q.drain = callback; + } ], function (err) { test.done(err); |