Permalink
Browse files

Add awaitAll.

  • Loading branch information...
1 parent 5edd209 commit c3b235f8abec783d1588099961d1bc63c717b4be @mbostock mbostock committed Nov 12, 2012
Showing with 62 additions and 43 deletions.
  1. +5 −4 README.md
  2. +1 −1 package.json
  3. +28 −14 queue.js
  4. +1 −1 queue.min.js
  5. +27 −23 test/queue-test.js
View
@@ -8,15 +8,15 @@ For example, if you wanted to stat two files in parallel:
queue()
.defer(fs.stat, __dirname + "/../Makefile")
.defer(fs.stat, __dirname + "/../package.json")
- .await(function(error, results) { console.log(results); });
+ .await(function(error, file1, file2) { console.log(file1, file2); });
```
Or, if you wanted to run a bazillion asynchronous tasks (here represented as an array of closures) serially:
```js
var q = queue(1);
tasks.forEach(function(t) { q.defer(t); });
-q.await(function(error, results) { console.log("all done!"); });
+q.awaitAll(function(error, results) { console.log("all done!"); });
```
Queue.js can be run inside Node.js or in a browser.
@@ -32,9 +32,10 @@ Constructs a new queue with the specified *parallelism*. If *parallelism* is not
Adds the specified *method* to the queue, with any optional *arguments*. The *method* is called with the optional arguments and a final callback argument, which should be called when the task has finished.
### queue.await(callback)
+### queue.awaitAll(callback)
-Sets the *callback* to be notified when all deferred tasks have finished.
+Sets the *callback* to be notified when all deferred tasks have finished. If *await* is used, each result is passed as a separate argument; if *awaitAll* is used, the entire array of results is passed as a single argument.
## Callbacks
-The callbacks follow the Node.js convention where the first argument is an optional error object, and the second is used to pass on the result of an operation.
+The callbacks follow the Node.js convention where the first argument is an optional error object, and the second is used to pass on the result of an operation. Queue.js does not directly support asynchronous functions that return multiple results; however, you can homogenize such functions by wrapping them and converting multiple results into a single object or array.
View
@@ -1,6 +1,6 @@
{
"name": "queue-async",
- "version": "0.0.2",
+ "version": "1.0.0",
"description": "A little helper for asynchronous JavaScript.",
"keywords": [
"asynchronous",
View
@@ -2,24 +2,24 @@
if (typeof module === "undefined") self.queue = queue;
else module.exports = queue;
- queue.version = "0.0.2";
+ queue.version = "1.0.0";
function queue(parallelism) {
var queue = {},
active = 0, // number of in-flight deferrals
remaining = 0, // number of deferrals remaining
- index = -1, // monotonically-increasing index
head, tail, // singly-linked list of deferrals
error = null,
results = [],
- await = noop;
+ await = noop,
+ awaitAll;
if (arguments.length < 1) parallelism = Infinity;
queue.defer = function() {
if (!error) {
var node = arguments;
- node.index = ++index;
+ node.index = results.push(undefined) - 1;
if (tail) tail.next = node, tail = tail.next;
else head = tail = node;
++remaining;
@@ -30,7 +30,15 @@
queue.await = function(f) {
await = f;
- if (!remaining) await(error, results);
+ awaitAll = false;
+ if (!remaining) notify();
+ return queue;
+ };
+
+ queue.awaitAll = function(f) {
+ await = f;
+ awaitAll = true;
+ if (!remaining) notify();
return queue;
};
@@ -45,24 +53,30 @@
++active;
a.push(function(e, r) {
--active;
- if (error) return;
- if (e) {
- if (remaining) {
- // clearing remaining cancels subsequent callbacks
- // clearing head stops queued tasks from being executed
- // setting error ignores subsequent calls to defer
- await(error = e, remaining = results = head = tail = null);
- }
+ if (error != null) return;
+ if (e != null) {
+ // clearing remaining cancels subsequent callbacks
+ // clearing head stops queued tasks from being executed
+ // setting error ignores subsequent calls to defer
+ error = e;
+ remaining = results = head = tail = null;
+ notify();
} else {
results[i] = r;
if (--remaining) pop();
- else await(null, results);
+ else notify();
}
});
f.apply(null, a);
}
}
+ function notify() {
+ if (error != null) await(error);
+ else if (awaitAll) await(null, results);
+ else await.apply(null, [null].concat(results));
+ }
+
return queue;
}
View

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.
View
@@ -21,14 +21,13 @@ suite.addBatch({
.defer(fs.stat, __dirname + "/../package.json")
.await(this.callback);
},
- "does not fail": function(error, results) {
+ "does not fail": function(error, one, two, three) {
assert.isNull(error);
},
- "successfully executes the three tasks": function(error, results) {
- assert.greater(results[0].size, 0);
- assert.greater(results[1].size, 0);
- assert.greater(results[2].size, 0);
- assert.equal(results.length, 3);
+ "successfully executes the three tasks": function(error, one, two, three) {
+ assert.greater(one.size, 0);
+ assert.greater(two.size, 0);
+ assert.greater(three.size, 0);
}
},
@@ -38,9 +37,9 @@ suite.addBatch({
.defer(function(callback) { callback(-1); })
.await(this.callback);
},
- "fails": function(error, results) {
+ "fails": function(error, result) {
assert.equal(error, -1);
- assert.isNull(results);
+ assert.isUndefined(result);
}
},
@@ -50,9 +49,9 @@ suite.addBatch({
.defer(function(callback) { process.nextTick(function() { callback(-1); }); })
.await(this.callback);
},
- "fails": function(error, results) {
+ "fails": function(error, result) {
assert.equal(error, -1);
- assert.isNull(results);
+ assert.isUndefined(result);
}
},
@@ -64,9 +63,11 @@ suite.addBatch({
.defer(function(callback) { setTimeout(function() { callback(-3); }, 200); })
.await(this.callback);
},
- "the first error is returned": function(error, results) {
+ "the first error is returned": function(error, one, two, three) {
assert.equal(error, -1);
- assert.isNull(results);
+ assert.isUndefined(one);
+ assert.isUndefined(two);
+ assert.isUndefined(three);
}
},
@@ -77,9 +78,10 @@ suite.addBatch({
.defer(function(callback) { process.nextTick(function() { callback(null, 'ok'); }); })
.await(this.callback);
},
- "the first error is returned": function(error, results) {
+ "the first error is returned": function(error, one, two) {
assert.equal(error, -1);
- assert.isNull(results);
+ assert.isUndefined(one);
+ assert.isUndefined(two);
}
},
@@ -91,9 +93,11 @@ suite.addBatch({
.defer(function(callback) { throw new Error(); })
.await(this.callback);
},
- "the first error prevents the other tasks from running": function(error, results) {
+ "the first error prevents the other tasks from running": function(error, one, two, three) {
assert.equal(error, -1);
- assert.isNull(results);
+ assert.isUndefined(one);
+ assert.isUndefined(two);
+ assert.isUndefined(three);
}
},
@@ -102,7 +106,7 @@ suite.addBatch({
var tasks = [], task = asynchronousTask(), n = 10, q = queue(1);
while (--n >= 0) tasks.push(task);
tasks.forEach(function(t) { q.defer(t); });
- q.await(this.callback)
+ q.awaitAll(this.callback)
},
"does not fail": function(error, results) {
assert.isNull(error);
@@ -126,7 +130,7 @@ suite.addBatch({
.defer(t)
.defer(t)
.defer(t)
- .await(this.callback);
+ .awaitAll(this.callback);
},
"does not fail": function(error, results) {
assert.isNull(error);
@@ -150,7 +154,7 @@ suite.addBatch({
.defer(t)
.defer(t)
.defer(t)
- .await(this.callback);
+ .awaitAll(this.callback);
},
"does not fail": function(error, results) {
assert.isNull(error);
@@ -174,7 +178,7 @@ suite.addBatch({
.defer(t)
.defer(t)
.defer(t)
- .await(this.callback);
+ .awaitAll(this.callback);
},
"does not fail": function(error, results) {
assert.isNull(error);
@@ -198,7 +202,7 @@ suite.addBatch({
.defer(t)
.defer(t)
.defer(t)
- .await(this.callback);
+ .awaitAll(this.callback);
},
"does not fail": function(error, results) {
assert.isNull(error);
@@ -222,7 +226,7 @@ suite.addBatch({
.defer(t)
.defer(t)
.defer(t)
- .await(this.callback);
+ .awaitAll(this.callback);
},
"does not fail": function(error, results) {
assert.isNull(error);
@@ -246,7 +250,7 @@ suite.addBatch({
.defer(t)
.defer(t)
.defer(t)
- .await(this.callback);
+ .awaitAll(this.callback);
},
"does not fail": function(error, results) {
assert.isNull(error);

0 comments on commit c3b235f

Please sign in to comment.