Skip to content

Commit

Permalink
Export d3_queue, not queue.
Browse files Browse the repository at this point in the history
This makes d3-queue consistent with the other D3 modules.
  • Loading branch information
mbostock committed Jan 27, 2016
1 parent a5d19a5 commit ea77e3d
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 51 deletions.
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# d3-queue

A **queue** evaluates zero or more *deferred* asynchronous tasks with configurable concurrency: you control how many tasks run at the same time. When all the tasks complete, or an error occurs, the queue passes the results to your *await* callback. This library is similar to [Async.js](https://github.com/caolan/async)’s [parallel](https://github.com/caolan/async#paralleltasks-callback) (when *concurrency* is infinite), [series](https://github.com/caolan/async#seriestasks-callback) (when *concurrency* is 1), and [queue](https://github.com/caolan/async#queue), but features a much smaller footprint: as of release 1.2, d3-queue is about 600 bytes gzipped, compared to 4,300 for Async.
A **queue** evaluates zero or more *deferred* asynchronous tasks with configurable concurrency: you control how many tasks run at the same time. When all the tasks complete, or an error occurs, the queue passes the results to your *await* callback. This library is similar to [Async.js](https://github.com/caolan/async)’s [parallel](https://github.com/caolan/async#paralleltasks-callback) (when *concurrency* is infinite), [series](https://github.com/caolan/async#seriestasks-callback) (when *concurrency* is 1), and [queue](https://github.com/caolan/async#queue), but features a much smaller footprint: as of release 2, d3-queue is about 600 bytes gzipped, compared to 4,300 for Async.

Each task is defined as a function that takes a callback as its last argument. For example, here’s a task that says hello after a short delay:

Expand All @@ -18,7 +18,7 @@ When a task completes, it must call the provided callback. The first argument to
To run multiple tasks simultaneously, create a queue, *defer* your tasks, and then register an *await* callback to be called when all of the tasks complete (or an error occurs):

```js
var q = queue();
var q = d3.queue();
q.defer(delayedHello);
q.defer(delayedHello);
q.await(function(error) {
Expand All @@ -30,7 +30,7 @@ q.await(function(error) {
Of course, you can also use a `for` loop to defer many tasks:

```js
var q = queue();
var q = d3.queue();

for (var i = 0; i < 1000; ++i) {
q.defer(delayedHello);
Expand All @@ -56,7 +56,7 @@ function delayedHello(name, delay, callback) {
Any additional arguments provided to [*queue*.defer](#queue_defer) are automatically passed along to the task function before the callback argument. You can also use method chaining for conciseness, avoiding the need for a local variable:

```js
queue()
d3.queue()
.defer(delayedHello, "Alice", 250)
.defer(delayedHello, "Bob", 500)
.defer(delayedHello, "Carol", 750)
Expand All @@ -69,7 +69,7 @@ queue()
The [asynchronous callback pattern](https://github.com/maxogden/art-of-node#callbacks) is very common in Node.js, so Queue works directly with many Node APIs. For example, to [stat two files](https://nodejs.org/dist/latest/docs/api/fs.html#fs_fs_stat_path_callback) concurrently:

```js
queue()
d3.queue()
.defer(fs.stat, __dirname + "/../Makefile")
.defer(fs.stat, __dirname + "/../package.json")
.await(function(error, file1, file2) {
Expand Down Expand Up @@ -97,7 +97,7 @@ function delayedHello(name, delay, callback) {
When you call [*queue*.abort](#queue_abort), any in-progress tasks will be immediately aborted; in addition, any pending (not-yet-started) tasks not be started. Note that you can also use *queue*.abort *without* abortable tasks, in which case pending tasks will be cancelled, though active tasks will continue to run. Conveniently, the [d3-request](https://github.com/d3/d3-request) library implements abort atop XMLHttpRequest. For example:

```js
var q = queue()
var q = d3.queue()
.defer(d3.request, "http://www.google.com:81")
.defer(d3.request, "http://www.google.com:81")
.defer(d3.request, "http://www.google.com:81")
Expand All @@ -114,14 +114,14 @@ To abort these requests, call `q.abort()`.
If you use NPM, `npm install d3-queue`. Otherwise, download the [latest release](https://github.com/d3/d3-queue/releases/latest). The released bundle supports AMD, CommonJS, and vanilla environments. You can also load directly from [d3js.org](https://d3js.org):

```html
<script src="https://d3js.org/queue.v1.min.js"></script>
<script src="https://d3js.org/d3-queue.v2.min.js"></script>
```

In a vanilla environment, a `queue` global function is exported. [Try d3-queue in your browser.](https://tonicdev.com/npm/d3-queue)
In a vanilla environment, a `d3_queue` global function is exported. [Try d3-queue in your browser.](https://tonicdev.com/npm/d3-queue)

## API Reference

<a href="#queue" name="queue">#</a> <b>queue</b>([<i>concurrency</i>])
<a href="#queue" name="queue">#</a> d3.<b>queue</b>([<i>concurrency</i>])

Constructs a new queue with the specified *concurrency*. If *concurrency* is not specified, the queue has infinite concurrency. Otherwise, *concurrency* is a positive integer. For example, if *concurrency* is 1, then all tasks will be run in series. If *concurrency* is 3, then at most three tasks will be allowed to proceed concurrently; this is useful, for example, when loading resources in a web browser.

Expand Down Expand Up @@ -152,7 +152,7 @@ Aborts any active tasks, invoking each active task’s *task*.abort function, if
Sets the *callback* to be invoked when all deferred tasks have finished. The first argument to the *callback* is the first error that occurred, or null if no error occurred. If an error occurred, there are no additional arguments to the callback. Otherwise, the *callback* is passed each result as an additional argument. For example:

```js
queue()
d3.queue()
.defer(fs.stat, __dirname + "/../Makefile")
.defer(fs.stat, __dirname + "/../package.json")
.await(function(error, file1, file2) { console.log(file1, file2); });
Expand All @@ -165,7 +165,7 @@ If all [deferred](#queue_defer) tasks have already completed, the callback will
Sets the *callback* to be invoked when all deferred tasks have finished. The first argument to the *callback* is the first error that occurred, or null if no error occurred. If an error occurred, there are no additional arguments to the callback. Otherwise, the *callback* is also passed an array of results as the second argument. For example:

```js
queue()
d3.queue()
.defer(fs.stat, __dirname + "/../Makefile")
.defer(fs.stat, __dirname + "/../package.json")
.awaitAll(function(error, files) { console.log(files); });
Expand Down
4 changes: 1 addition & 3 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
import queue from "./src/queue";

export default queue;
export {default as queue} from "./src/queue";
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "d3-queue",
"version": "1.2.2",
"version": "2.0.0",
"description": "A minimalist approach to escaping callback hell.",
"keywords": [
"d3",
Expand All @@ -14,16 +14,16 @@
"name": "Mike Bostock",
"url": "http://bost.ocks.org/mike"
},
"main": "build/queue.js",
"main": "build/d3-queue.js",
"jsnext:main": "index",
"repository": {
"type": "git",
"url": "https://github.com/d3/d3-queue.git"
},
"scripts": {
"pretest": "mkdir -p build && node -e 'process.stdout.write(\"import queue from \\\"../index\\\"; queue.version = \\\"\" + require(\"./package.json\").version + \"\\\"; export default queue;\");' > build/bundle.js && rollup -f umd -u queue -n queue -o build/queue.js -- build/bundle.js",
"pretest": "mkdir -p build && node -e 'process.stdout.write(\"var version = \\\"\" + require(\"./package.json\").version + \"\\\"; export * from \\\"../index\\\"; export {version};\");' > build/bundle.js && rollup -f umd -u d3-queue -n d3_queue -o build/d3-queue.js -- build/bundle.js",
"test": "faucet `find test -name '*-test.js'` && eslint index.js src",
"prepublish": "npm run test && uglifyjs build/queue.js -c -m -o build/queue.min.js && rm -f build/queue.zip && zip -j build/queue.zip -- LICENSE README.md build/queue.js build/queue.min.js"
"prepublish": "npm run test && uglifyjs build/d3-queue.js -c -m -o build/d3-queue.min.js && rm -f build/d3-queue.zip && zip -j build/d3-queue.zip -- LICENSE README.md build/d3-queue.js build/d3-queue.min.js"
},
"devDependencies": {
"faucet": "0.0",
Expand Down
66 changes: 33 additions & 33 deletions test/queue-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ tape("version is semantic", function(test) {
});

tape("example queue of fs.stat", function(test) {
queue()
queue.queue()
.defer(fs.stat, __dirname + "/../index.js")
.defer(fs.stat, __dirname + "/../README.md")
.defer(fs.stat, __dirname + "/../package.json")
Expand All @@ -28,31 +28,31 @@ tape("example queue of fs.stat", function(test) {
});

tape("if the concurrency is invalid, an Error is thrown", function(test) {
test.throws(function() { queue(NaN); }, /Error/);
test.throws(function() { queue(0); }, /Error/);
test.throws(function() { queue(-1); }, /Error/);
test.throws(function() { queue.queue(NaN); }, /Error/);
test.throws(function() { queue.queue(0); }, /Error/);
test.throws(function() { queue.queue(-1); }, /Error/);
test.end();
});

tape("queue.defer throws an error if passed a non-function", function(test) {
test.throws(function() { queue().defer(42); }, /Error/);
test.throws(function() { queue.queue().defer(42); }, /Error/);
test.end();
});

tape("queue.await throws an error if passed a non-function", function(test) {
var task = asynchronousTask();
test.throws(function() { queue().defer(task).await(42); }, /Error/);
test.throws(function() { queue.queue().defer(task).await(42); }, /Error/);
test.end();
});

tape("queue.awaitAll throws an error if passed a non-function", function(test) {
var task = asynchronousTask();
test.throws(function() { queue().defer(task).awaitAll(42); }, /Error/);
test.throws(function() { queue.queue().defer(task).awaitAll(42); }, /Error/);
test.end();
});

tape("in a queue of a single synchronous task that errors, the error is returned", function(test) {
queue()
queue.queue()
.defer(function(callback) { callback(-1); })
.await(callback);

Expand All @@ -64,7 +64,7 @@ tape("in a queue of a single synchronous task that errors, the error is returned
});

tape("in a queue of a single asynchronous task that errors, the error is returned", function(test) {
queue()
queue.queue()
.defer(function(callback) { process.nextTick(function() { callback(-1); }); })
.await(callback);

Expand All @@ -76,7 +76,7 @@ tape("in a queue of a single asynchronous task that errors, the error is returne
});

tape("in a queue with multiple tasks that error, the first error is returned", function(test) {
queue()
queue.queue()
.defer(function(callback) { setTimeout(function() { callback(-2); }, 100); })
.defer(function(callback) { process.nextTick(function() { callback(-1); }); })
.defer(function(callback) { setTimeout(function() { callback(-3); }, 200); })
Expand All @@ -92,7 +92,7 @@ tape("in a queue with multiple tasks that error, the first error is returned", f
});

tape("in a queue with multiple tasks where one errors, the first error is returned", function(test) {
queue()
queue.queue()
.defer(function(callback) { process.nextTick(function() { callback(-1); }); })
.defer(function(callback) { process.nextTick(function() { callback(null, 'ok'); }); })
.await(callback);
Expand All @@ -106,7 +106,7 @@ tape("in a queue with multiple tasks where one errors, the first error is return
});

tape("in a queue with multiple synchronous tasks that error, the first error prevents the other tasks from running", function(test) {
queue()
queue.queue()
.defer(function(callback) { callback(-1); })
.defer(function(callback) { callback(-2); })
.defer(function(callback) { throw new Error; })
Expand All @@ -122,7 +122,7 @@ tape("in a queue with multiple synchronous tasks that error, the first error pre
});

tape("in a queue with a task that throws an error synchronously, the error is reported to the await callback", function(test) {
queue()
queue.queue()
.defer(function(callback) { throw new Error("foo"); })
.await(callback);

Expand All @@ -133,7 +133,7 @@ tape("in a queue with a task that throws an error synchronously, the error is re
});

tape("in a queue with a task that throws an error after calling back, the error is ignored", function(test) {
queue()
queue.queue()
.defer(function(callback) { setTimeout(function() { callback(null, 1); }, 100); })
.defer(function(callback) { callback(null, 2); process.nextTick(function() { callback(new Error("foo")); }); })
.await(callback);
Expand All @@ -147,7 +147,7 @@ tape("in a queue with a task that throws an error after calling back, the error
});

tape("in a queue with a task that doesn’t terminate and another that errors synchronously, the error is still reported", function(test) {
queue()
queue.queue()
.defer(function() { /* Run forever! */ })
.defer(function(callback) { callback(new Error("foo")); })
.await(callback);
Expand All @@ -162,7 +162,7 @@ tape("a serial queue of asynchronous closures processes tasks serially", functio
var tasks = [],
task = asynchronousTask(),
n = 10,
q = queue(1);
q = queue.queue(1);

while (--n >= 0) tasks.push(task);
tasks.forEach(function(t) { q.defer(t); });
Expand All @@ -189,7 +189,7 @@ tape("a serial queue of asynchronous closures processes tasks serially", functio
tape("a fully-concurrent queue of ten asynchronous tasks executes all tasks concurrently", function(test) {
var t = asynchronousTask();

queue()
queue.queue()
.defer(t)
.defer(t)
.defer(t)
Expand Down Expand Up @@ -223,7 +223,7 @@ tape("a fully-concurrent queue of ten asynchronous tasks executes all tasks conc
tape("a partly-concurrent queue of ten asynchronous tasks executes at most three tasks concurrently", function(test) {
var t = asynchronousTask();

queue(3)
queue.queue(3)
.defer(t)
.defer(t)
.defer(t)
Expand Down Expand Up @@ -257,7 +257,7 @@ tape("a partly-concurrent queue of ten asynchronous tasks executes at most three
tape("a serialized queue of ten asynchronous tasks executes all tasks in series", function(test) {
var t = asynchronousTask();

queue(1)
queue.queue(1)
.defer(t)
.defer(t)
.defer(t)
Expand Down Expand Up @@ -291,7 +291,7 @@ tape("a serialized queue of ten asynchronous tasks executes all tasks in series"
tape("a serialized queue of ten deferred synchronous tasks executes all tasks in series, within the callback of the first task", function(test) {
var t = deferredSynchronousTask();

queue(1)
queue.queue(1)
.defer(t)
.defer(t)
.defer(t)
Expand Down Expand Up @@ -327,7 +327,7 @@ tape("a serialized queue of ten deferred synchronous tasks executes all tasks in
tape("a partly-concurrent queue of ten synchronous tasks executes all tasks in series", function(test) {
var t = synchronousTask();

queue(3)
queue.queue(3)
.defer(t)
.defer(t)
.defer(t)
Expand Down Expand Up @@ -361,7 +361,7 @@ tape("a partly-concurrent queue of ten synchronous tasks executes all tasks in s
tape("a serialized queue of ten synchronous tasks executes all tasks in series", function(test) {
var t = synchronousTask();

queue(1)
queue.queue(1)
.defer(t)
.defer(t)
.defer(t)
Expand Down Expand Up @@ -394,7 +394,7 @@ tape("a serialized queue of ten synchronous tasks executes all tasks in series",

tape("a huge queue of deferred synchronous tasks does not throw a RangeError", function(test) {
var t = deferredSynchronousTask(),
q = queue(),
q = queue.queue(),
n = 200000;

for (var i = 0; i < n; ++i) q.defer(t);
Expand All @@ -409,7 +409,7 @@ tape("a huge queue of deferred synchronous tasks does not throw a RangeError", f
});

tape("if a task calls back successfully more than once, subsequent calls are ignored", function(test) {
queue()
queue.queue()
.defer(function(callback) { setTimeout(function() { callback(null, 1); }, 100); })
.defer(function(callback) { callback(null, 2); process.nextTick(function() { callback(null, -1); }); })
.defer(function(callback) { callback(null, 3); process.nextTick(function() { callback(new Error("foo")); }); })
Expand All @@ -427,7 +427,7 @@ tape("if a task calls back successfully more than once, subsequent calls are ign
});

tape("if a task calls back with an error more than once, subsequent calls are ignored", function(test) {
queue()
queue.queue()
.defer(function(callback) { setTimeout(function() { callback(null, 1); }, 100); })
.defer(function(callback) { callback(new Error("foo")); process.nextTick(function() { callback(new Error("bar")); }); })
.defer(function(callback) { process.nextTick(function() { callback(new Error("bar")); }); setTimeout(function() { callback(new Error("baz")); }, 100); })
Expand All @@ -440,7 +440,7 @@ tape("if a task calls back with an error more than once, subsequent calls are ig
});

tape("if a task throws an error aftering calling back synchronously, the error is ignored", function(test) {
queue()
queue.queue()
.defer(function(callback) { callback(null, 1); throw new Error; })
.await(callback);

Expand All @@ -454,7 +454,7 @@ tape("if a task throws an error aftering calling back synchronously, the error i
tape("if a task errors, it is not subsequently aborted", function(test) {
var aborted = false;

var q = queue()
var q = queue.queue()
.defer(function(callback) { process.nextTick(function() { callback(new Error("foo")); }); return {abort: function() { aborted = true; }}; })
.await(callback);

Expand All @@ -466,7 +466,7 @@ tape("if a task errors, it is not subsequently aborted", function(test) {
});

tape("a task that defers another task is allowed", function(test) {
var q = queue();
var q = queue.queue();

q.defer(function(callback) {
callback(null);
Expand All @@ -477,14 +477,14 @@ tape("a task that defers another task is allowed", function(test) {
});

tape("a falsey error is still considered an error", function(test) {
queue()
queue.queue()
.defer(function(callback) { callback(0); })
.defer(function() { throw new Error; })
.await(function(error) { test.equal(error, 0); test.end(); });
});

tape("if the await callback is set during abort, it only gets called once", function(test) {
var q = queue();
var q = queue.queue();
q.defer(function() { return {abort: function() { q.await(callback); }}; });
q.defer(function() { throw new Error("foo"); });

Expand All @@ -498,7 +498,7 @@ tape("aborts a queue of partially-completed asynchronous tasks", function(test)
var shortTask = abortableTask(50),
longTask = abortableTask(5000);

var q = queue()
var q = queue.queue()
.defer(shortTask)
.defer(longTask)
.defer(shortTask)
Expand Down Expand Up @@ -527,7 +527,7 @@ tape("aborts a queue of partially-completed asynchronous tasks", function(test)
tape("aborts an entire queue of asynchronous tasks", function(test) {
var longTask = abortableTask(5000);

var q = queue()
var q = queue.queue()
.defer(longTask)
.defer(longTask)
.defer(longTask)
Expand All @@ -551,7 +551,7 @@ tape("does not abort tasks that have not yet started", function(test) {
var shortTask = abortableTask(50),
longTask = abortableTask(5000);

var q = queue(2) // enough for two short tasks to run
var q = queue.queue(2) // enough for two short tasks to run
.defer(shortTask)
.defer(longTask)
.defer(shortTask)
Expand Down

0 comments on commit ea77e3d

Please sign in to comment.