Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

added asnyc.unwind to prevent Stack Overflow in whilst/until if used with synchronous functions #135

Closed
wants to merge 2 commits into from

2 participants

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on May 31, 2012
  1. @sokra

    added test for #133

    sokra authored
  2. @sokra
This page is out of date. Refresh to see the latest.
Showing with 100 additions and 12 deletions.
  1. +37 −0 README.md
  2. +39 −12 lib/async.js
  3. +24 −0 test/test-async.js
View
37 README.md
@@ -92,6 +92,7 @@ So far its been tested in IE6, IE7, IE8, FF3.6 and Chrome 5. Usage:
* [iterator](#iterator)
* [apply](#apply)
* [nextTick](#nextTick)
+* [unwind](#unwind)
### Utils
@@ -919,6 +920,42 @@ __Example__
});
call_order.push('one')
+---------------------------------------
+
+<a name="unwind" />
+### unwind(function, callback)
+
+Calls a asynchronous function. If the function is not really asynchronous, the
+callback is not called, but `unwind` returns the arguments as result.
+
+This is useful to prevent stack overflows in asynchronous loop with not really
+asynchronous functions.
+
+__Arguments__
+
+* function - A function which should be called. `task(callback)`
+* callback - The callback to call if the function is really asynchronous.
+
+__Returns__
+
+A Array containing the arguments passed from the task to the callback.
+`unwind` only returns the array if task was synchronous.
+If task is asynchronous `unwind` do not return anything.
+
+__Example__
+
+ function may(callback) {
+ if (Math.random() < 0.5) {
+ setTimeout(callback.bind(null, "async"), 1000);
+ } else {
+ callback("sync");
+ }
+ }
+ var sync = async.unwind(may, console.log);
+ if (sync) { // only if may was synchronous
+ console.log(sync[0]);
+ }
+
## Utils
View
51 lib/async.js
@@ -446,6 +446,19 @@
wrapIterator(async.iterator(tasks))();
};
+ async.unwind = function(task, callback) {
+ var result;
+ var cb = function(err, value) {
+ result = Array.prototype.slice.call(arguments, 0);
+ };
+ task(function(err, value) { cb.apply(null, arguments); });
+ if (!result) {
+ cb = callback || function () {};
+ } else {
+ return result;
+ }
+ }
+
async.parallel = function (tasks, callback) {
callback = callback || function () {};
if (tasks.constructor === Array) {
@@ -550,31 +563,45 @@
async.concatSeries = doSeries(_concat);
async.whilst = function (test, iterator, callback) {
- if (test()) {
- iterator(function (err) {
+ while (test()) {
+ function iteratorCallback(err) {
if (err) {
return callback(err);
}
async.whilst(test, iterator, callback);
- });
- }
- else {
- callback();
+ }
+ var sync = async.unwind(iterator, iteratorCallback);
+ if (sync) {
+ if (sync[0]) {
+ return callback(sync[0]);
+ }
+ continue;
+ } else {
+ return;
+ }
}
+ callback();
};
async.until = function (test, iterator, callback) {
- if (!test()) {
- iterator(function (err) {
+ while (!test()) {
+ function iteratorCallback(err) {
if (err) {
return callback(err);
}
async.until(test, iterator, callback);
- });
- }
- else {
- callback();
+ }
+ var sync = async.unwind(iterator, iteratorCallback);
+ if (sync) {
+ if (sync[0]) {
+ return callback(sync[0]);
+ }
+ continue;
+ } else {
+ return;
+ }
}
+ callback();
};
async.queue = function (worker, concurrency) {
View
24 test/test-async.js
@@ -1212,6 +1212,30 @@ exports['whilst'] = function (test) {
);
};
+exports['whilst/until sync'] = function (test) {
+ var i = 0, j = 0;
+ var testFuncWhile = function() { return i < 100000; }
+ var testFuncUntil = function() { return i >= 100000; }
+ var iter = function(c) {
+ i++;
+ j++;
+ c();
+ }
+ var check = function() {
+ test.equals(i, 100000);
+ test.equals(j, 100000);
+ test.done();
+ }
+
+ // This will stack overflow if we wouldn't care about it.
+ async.whilst(testFuncWhile, iter, function() {
+ test.equals(i, 100000);
+ test.equals(j, 100000);
+ i = j = 0;
+ async.until(testFuncUntil, iter, check);
+ });
+};
+
exports['queue'] = function (test) {
var call_order = [],
delays = [160,80,240,80];
Something went wrong with that request. Please try again.