summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.jshintrc19
-rw-r--r--.travis.yml2
-rw-r--r--Makefile2
-rw-r--r--README.md136
-rw-r--r--bower.json38
-rw-r--r--component.json21
-rw-r--r--[-rwxr-xr-x]lib/async.js176
-rw-r--r--package.json86
-rwxr-xr-xsupport/sync-package-managers.js53
-rwxr-xr-xtest/test-async.js270
10 files changed, 681 insertions, 122 deletions
diff --git a/.jshintrc b/.jshintrc
new file mode 100644
index 0000000..3a2825a
--- /dev/null
+++ b/.jshintrc
@@ -0,0 +1,19 @@
+{
+ // Enforcing options
+ "eqeqeq": false,
+ "forin": true,
+ "indent": 4,
+ "noarg": true,
+ "undef": true,
+ "unused": true,
+ "trailing": true,
+
+ // Relaxing options
+ "asi": false,
+ "eqnull": true,
+ "evil": true,
+ "expr": false,
+ "laxcomma": true,
+ "loopfunc": true,
+ "sub": true
+}
diff --git a/.travis.yml b/.travis.yml
index 6e5919d..6064ca0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,3 +1,5 @@
language: node_js
node_js:
- "0.10"
+ - "0.12"
+ - "iojs"
diff --git a/Makefile b/Makefile
index bad647c..4b0f23c 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
PACKAGE = asyncjs
NODEJS = $(if $(shell test -f /usr/bin/nodejs && echo "true"),nodejs,node)
-CWD := $(shell pwd)
+CWD := "$(shell pwd)"
NODEUNIT = $(CWD)/node_modules/nodeunit/bin/nodeunit
UGLIFY = $(CWD)/node_modules/uglify-js/bin/uglifyjs
NODELINT = $(CWD)/node_modules/nodelint/nodelint
diff --git a/README.md b/README.md
index f900495..cc55da2 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,21 @@
# Async.js
[![Build Status via Travis CI](https://travis-ci.org/caolan/async.svg?branch=master)](https://travis-ci.org/caolan/async)
+[![NPM version](http://img.shields.io/npm/v/async.svg)](https://www.npmjs.org/package/async)
Async is a utility module which provides straight-forward, powerful functions
for working with asynchronous JavaScript. Although originally designed for
-use with [Node.js](http://nodejs.org), it can also be used directly in the
-browser. Also supports [component](https://github.com/component/component).
+use with [Node.js](http://nodejs.org) and installable via `npm install async`,
+it can also be used directly in the browser.
+
+Async is also installable via:
+
+- [bower](http://bower.io/): `bower install async`
+- [component](https://github.com/component/component): `component install
+ caolan/async`
+- [jam](http://jamjs.org/): `jam install async`
+- [spm](http://spmjs.io/): `spm install async`
Async provides around 20 functions that include the usual 'functional'
suspects (`map`, `reduce`, `filter`, `each`…) as well as some common patterns
@@ -115,6 +124,9 @@ Usage:
* [`each`](#each)
* [`eachSeries`](#eachSeries)
* [`eachLimit`](#eachLimit)
+* [`forEachOf`](#forEachOf)
+* [`forEachOfSeries`](#forEachOfSeries)
+* [`forEachOfLimit`](#forEachOfLimit)
* [`map`](#map)
* [`mapSeries`](#mapSeries)
* [`mapLimit`](#mapLimit)
@@ -187,7 +199,8 @@ __Arguments__
* `iterator(item, callback)` - A function to apply to each item in `arr`.
The iterator is passed a `callback(err)` which must be called once it has
completed. If no error has occurred, the `callback` should be run without
- arguments or with an explicit `null` argument.
+ arguments or with an explicit `null` argument. The array index is not passed
+ to the iterator. If you need the index, use [`forEachOf`](#forEachOf).
* `callback(err)` - A callback which is called when all `iterator` functions
have finished, or an error occurs.
@@ -206,7 +219,7 @@ async.each(openFiles, saveFile, function(err){
```js
// assuming openFiles is an array of file names
-async.each(openFiles, function( file, callback) {
+async.each(openFiles, function(file, callback) {
// Perform operation on file here.
console.log('Processing file ' + file);
@@ -278,6 +291,67 @@ async.eachLimit(documents, 20, requestApi, function(err){
---------------------------------------
+<a name="forEachOf" />
+<a name="eachOf" />
+
+### forEachOf(obj, iterator, callback)
+
+Like `each`, except that it iterates over objects, and passes the key as the second argument to the iterator.
+
+__Arguments__
+
+* `obj` - An object or array to iterate over.
+* `iterator(item, key, callback)` - A function to apply to each item in `obj`.
+The `key` is the item's key, or index in the case of an array. The iterator is
+passed a `callback(err)` which must be called once it has completed. If no
+error has occurred, the callback should be run without arguments or with an
+explicit `null` argument.
+* `callback(err)` - A callback which is called when all `iterator` functions have finished, or an error occurs.
+
+__Example__
+
+```js
+var obj = {dev: "/dev.json", test: "/test.json", prod: "/prod.json"};
+var configs = {};
+
+async.forEachOf(obj, function (value, key, callback) {
+ fs.readFile(__dirname + value, "utf8", function (err, data) {
+ if (err) return callback(err);
+ try {
+ configs[key] = JSON.parse(data);
+ } catch (e) {
+ return callback(e);
+ }
+ callback();
+ })
+}, function (err) {
+ if (err) console.error(err.message);
+ // configs is now a map of JSON data
+ doSomethingWith(configs);
+})
+```
+
+---------------------------------------
+
+<a name="forEachOfSeries" />
+<a name="eachOfSeries" />
+
+### forEachOfSeries(obj, iterator, callback)
+
+Like [`forEachOf`](#forEachOf), except only one `iterator` is run at a time. The order of execution is not guaranteed for objects, but it will be guaranteed for arrays.
+
+---------------------------------------
+
+<a name="forEachOfLimit" />
+<a name="eachOfLimit" />
+
+### forEachOfLimit(obj, limit, iterator, callback)
+
+Like [`forEachOf`](#forEachOf), except the number of `iterator`s running at a given time is controlled by `limit`.
+
+
+---------------------------------------
+
<a name="map" />
### map(arr, iterator, callback)
@@ -540,14 +614,14 @@ By modifying the callback parameter the sorting order can be influenced:
```js
//ascending order
async.sortBy([1,9,3,5], function(x, callback){
- callback(err, x);
+ callback(null, x);
}, function(err,result){
//result callback
} );
//descending order
async.sortBy([1,9,3,5], function(x, callback){
- callback(err, x*-1); //<- x*-1 instead of x, turns the order around
+ callback(null, x*-1); //<- x*-1 instead of x, turns the order around
}, function(err,result){
//result callback
} );
@@ -917,19 +991,19 @@ __Example__
```js
async.waterfall([
- function(callback){
+ function(callback) {
callback(null, 'one', 'two');
},
- function(arg1, arg2, callback){
+ function(arg1, arg2, callback) {
// arg1 now equals 'one' and arg2 now equals 'two'
callback(null, 'three');
},
- function(arg1, callback){
+ function(arg1, callback) {
// arg1 now equals 'three'
callback(null, 'done');
}
], function (err, result) {
- // result now equals 'done'
+ // result now equals 'done'
});
```
@@ -976,7 +1050,8 @@ add1mul3(4, function (err, result) {
### seq(fn1, fn2...)
Version of the compose function that is more natural to read.
-Each following function consumes the return value of the latter function.
+Each function consumes the return value of the previous function.
+It is the equivalent of [`compose`](#compose) with the arguments reversed.
Each function is executed with the `this` binding of the composed function.
@@ -993,28 +1068,20 @@ __Example__
// This example uses `seq` function to avoid overnesting and error
// handling clutter.
app.get('/cats', function(request, response) {
- function handleError(err, data, callback) {
- if (err) {
- console.error(err);
- response.json({ status: 'error', message: err.message });
- }
- else {
- callback(data);
- }
- }
var User = request.models.User;
async.seq(
_.bind(User.get, User), // 'User.get' has signature (id, callback(err, data))
- handleError,
function(user, fn) {
user.getCats(fn); // 'getCats' has signature (callback(err, data))
- },
- handleError,
- function(cats) {
+ }
+ )(req.session.user_id, function (err, cats) {
+ if (err) {
+ console.error(err);
+ response.json({ status: 'error', message: err.message });
+ } else {
response.json({ status: 'ok', message: 'Cats found', data: cats });
}
- )(req.session.user_id);
- }
+ });
});
```
@@ -1051,7 +1118,7 @@ async.each(
---------------------------------------
<a name="applyEachSeries" />
-### applyEachSeries(arr, iterator, callback)
+### applyEachSeries(arr, args..., callback)
The same as [`applyEach`](#applyEach) only the functions are applied in series.
@@ -1096,7 +1163,7 @@ methods:
* `paused` - a boolean for determining whether the queue is in a paused state
* `pause()` - a function that pauses the processing of tasks until `resume()` is called.
* `resume()` - a function that resumes the processing of queued tasks when the queue is paused.
-* `kill()` - a function that empties remaining tasks from the queue forcing it to go idle.
+* `kill()` - a function that removes the `drain` callback and empties remaining tasks from the queue forcing it to go idle.
__Example__
@@ -1126,7 +1193,7 @@ q.push({name: 'bar'}, function (err) {
// add some items to the queue (batch-wise)
q.push([{name: 'baz'},{name: 'bay'},{name: 'bax'}], function (err) {
- console.log('finished processing bar');
+ console.log('finished processing item');
});
// add some items to the front of the queue
@@ -1353,7 +1420,7 @@ new tasks much easier (and the code more readable).
Attempts to get a successful response from `task` no more than `times` times before
returning an error. If the task is successful, the `callback` will be passed the result
-of the successfull task. If all attemps fail, the callback will be passed the error and
+of the successful task. If all attempts fail, the callback will be passed the error and
result (if any) of the final attempt.
__Arguments__
@@ -1478,7 +1545,7 @@ three
---------------------------------------
<a name="nextTick" />
-### nextTick(callback)
+### nextTick(callback), setImmediate(callback)
Calls `callback` on a later loop around the event loop. In Node.js this just
calls `process.nextTick`; in the browser it falls back to `setImmediate(callback)`
@@ -1511,7 +1578,8 @@ you would use with [`map`](#map).
__Arguments__
* `n` - The number of times to run the function.
-* `callback` - The function to call `n` times.
+* `iterator` - The function to call `n` times.
+* `callback` - see [`map`](#map)
__Example__
@@ -1549,13 +1617,15 @@ Caches the results of an `async` function. When creating a hash to store functio
results against, the callback is omitted from the hash and an optional hash
function can be used.
+If no hash function is specified, the first argument is used as a hash key, which may work reasonably if it is a string or a data type that converts to a distinct string. Note that objects and arrays will not behave reasonably. Neither will cases where the other arguments are significant. In such cases, specify your own hash function.
+
The cache of results is exposed as the `memo` property of the function returned
by `memoize`.
__Arguments__
* `fn` - The function to proxy and cache results from.
-* `hasher` - Tn optional function for generating a custom hash for storing
+* `hasher` - An optional function for generating a custom hash for storing
results. It has all the arguments applied to it apart from the callback, and
must be synchronous.
diff --git a/bower.json b/bower.json
new file mode 100644
index 0000000..1817688
--- /dev/null
+++ b/bower.json
@@ -0,0 +1,38 @@
+{
+ "name": "async",
+ "description": "Higher-order functions and common patterns for asynchronous code",
+ "version": "0.9.2",
+ "main": "lib/async.js",
+ "keywords": [
+ "async",
+ "callback",
+ "utility",
+ "module"
+ ],
+ "license": "MIT",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/caolan/async.git"
+ },
+ "devDependencies": {
+ "nodeunit": ">0.0.0",
+ "uglify-js": "1.2.x",
+ "nodelint": ">0.0.0",
+ "lodash": ">=2.4.1"
+ },
+ "moduleType": [
+ "amd",
+ "globals",
+ "node"
+ ],
+ "ignore": [
+ "**/.*",
+ "node_modules",
+ "bower_components",
+ "test",
+ "tests"
+ ],
+ "authors": [
+ "Caolan McMahon"
+ ]
+} \ No newline at end of file
diff --git a/component.json b/component.json
index bbb0115..5003a7c 100644
--- a/component.json
+++ b/component.json
@@ -1,11 +1,16 @@
{
"name": "async",
- "repo": "caolan/async",
"description": "Higher-order functions and common patterns for asynchronous code",
- "version": "0.1.23",
- "keywords": [],
- "dependencies": {},
- "development": {},
- "main": "lib/async.js",
- "scripts": [ "lib/async.js" ]
-}
+ "version": "0.9.2",
+ "keywords": [
+ "async",
+ "callback",
+ "utility",
+ "module"
+ ],
+ "license": "MIT",
+ "repository": "caolan/async",
+ "scripts": [
+ "lib/async.js"
+ ]
+} \ No newline at end of file
diff --git a/lib/async.js b/lib/async.js
index a13f835..108bc9d 100755..100644
--- a/lib/async.js
+++ b/lib/async.js
@@ -10,11 +10,21 @@
(function () {
var async = {};
+ var noop = function () {};
// global on the server, window in the browser
var root, previous_async;
- root = this;
+ if (typeof window == 'object' && this === window) {
+ root = window;
+ }
+ else if (typeof global == 'object' && this === global) {
+ root = global;
+ }
+ else {
+ root = this;
+ }
+
if (root != null) {
previous_async = root.async;
}
@@ -42,9 +52,6 @@
};
var _each = function (arr, iterator) {
- if (arr.forEach) {
- return arr.forEach(iterator);
- }
for (var i = 0; i < arr.length; i += 1) {
iterator(arr[i], i, arr);
}
@@ -71,6 +78,14 @@
return memo;
};
+ var _forEachOf = function (object, iterator) {
+ for (key in object) {
+ if (object.hasOwnProperty(key)) {
+ iterator(object[key], key);
+ }
+ }
+ };
+
var _keys = function (obj) {
if (Object.keys) {
return Object.keys(obj);
@@ -116,7 +131,7 @@
}
async.each = function (arr, iterator, callback) {
- callback = callback || function () {};
+ callback = callback || noop;
if (!arr.length) {
return callback();
}
@@ -127,7 +142,7 @@
function done(err) {
if (err) {
callback(err);
- callback = function () {};
+ callback = noop;
}
else {
completed += 1;
@@ -140,7 +155,7 @@
async.forEach = async.each;
async.eachSeries = function (arr, iterator, callback) {
- callback = callback || function () {};
+ callback = callback || noop;
if (!arr.length) {
return callback();
}
@@ -149,7 +164,7 @@
iterator(arr[completed], function (err) {
if (err) {
callback(err);
- callback = function () {};
+ callback = noop;
}
else {
completed += 1;
@@ -166,6 +181,7 @@
};
async.forEachSeries = async.eachSeries;
+
async.eachLimit = function (arr, limit, iterator, callback) {
var fn = _eachLimit(limit);
fn.apply(null, [arr, iterator, callback]);
@@ -175,7 +191,7 @@
var _eachLimit = function (limit) {
return function (arr, iterator, callback) {
- callback = callback || function () {};
+ callback = callback || noop;
if (!arr.length || limit <= 0) {
return callback();
}
@@ -194,7 +210,7 @@
iterator(arr[started - 1], function (err) {
if (err) {
callback(err);
- callback = function () {};
+ callback = noop;
}
else {
completed += 1;
@@ -213,6 +229,115 @@
};
+
+ async.forEachOf = async.eachOf = function (object, iterator, callback) {
+ callback = callback || function () {};
+ var size = object.length || _keys(object).length;
+ var completed = 0
+ if (!size) {
+ return callback();
+ }
+ _forEachOf(object, function (value, key) {
+ iterator(object[key], key, function (err) {
+ if (err) {
+ callback(err);
+ callback = function () {};
+ } else {
+ completed += 1;
+ if (completed === size) {
+ callback(null);
+ }
+ }
+ });
+ });
+ };
+
+ async.forEachOfSeries = async.eachOfSeries = function (obj, iterator, callback) {
+ callback = callback || function () {};
+ var keys = _keys(obj);
+ var size = keys.length;
+ if (!size) {
+ return callback();
+ }
+ var completed = 0;
+ var iterate = function () {
+ var sync = true;
+ var key = keys[completed];
+ iterator(obj[key], key, function (err) {
+ if (err) {
+ callback(err);
+ callback = function () {};
+ }
+ else {
+ completed += 1;
+ if (completed >= size) {
+ callback(null);
+ }
+ else {
+ if (sync) {
+ async.nextTick(iterate);
+ }
+ else {
+ iterate();
+ }
+ }
+ }
+ });
+ sync = false;
+ };
+ iterate();
+ };
+
+
+
+ async.forEachOfLimit = async.eachOfLimit = function (obj, limit, iterator, callback) {
+ _forEachOfLimit(limit)(obj, iterator, callback);
+ };
+
+ var _forEachOfLimit = function (limit) {
+
+ return function (obj, iterator, callback) {
+ callback = callback || function () {};
+ var keys = _keys(obj);
+ var size = keys.length;
+ if (!size || limit <= 0) {
+ return callback();
+ }
+ var completed = 0;
+ var started = 0;
+ var running = 0;
+
+ (function replenish () {
+ if (completed >= size) {
+ return callback();
+ }
+
+ while (running < limit && started < size) {
+ started += 1;
+ running += 1;
+ var key = keys[started - 1];
+ iterator(obj[key], key, function (err) {
+ if (err) {
+ callback(err);
+ callback = function () {};
+ }
+ else {
+ completed += 1;
+ running -= 1;
+ if (completed >= size) {
+ callback();
+ }
+ else {
+ replenish();
+ }
+ }
+ });
+ }
+ })();
+ };
+ };
+
+
var doParallel = function (fn) {
return function () {
var args = Array.prototype.slice.call(arguments);
@@ -345,7 +470,7 @@
iterator(x, function (result) {
if (result) {
main_callback(x);
- main_callback = function () {};
+ main_callback = noop;
}
else {
callback();
@@ -363,7 +488,7 @@
iterator(x, function (v) {
if (v) {
main_callback(true);
- main_callback = function () {};
+ main_callback = noop;
}
callback();
});
@@ -379,7 +504,7 @@
iterator(x, function (v) {
if (!v) {
main_callback(false);
- main_callback = function () {};
+ main_callback = noop;
}
callback();
});
@@ -417,7 +542,7 @@
};
async.auto = function (tasks, callback) {
- callback = callback || function () {};
+ callback = callback || noop;
var keys = _keys(tasks);
var remainingTasks = keys.length
if (!remainingTasks) {
@@ -449,7 +574,7 @@
if (!remainingTasks) {
var theCallback = callback;
// prevent final callback from calling itself if it errors
- callback = function () {};
+ callback = noop;
theCallback(null, results);
}
@@ -470,7 +595,7 @@
safeResults[k] = args;
callback(err, safeResults);
// stop subsequent errors hitting callback multiple times
- callback = function () {};
+ callback = noop;
}
else {
results[k] = args;
@@ -478,6 +603,17 @@
}
};
var requires = task.slice(0, Math.abs(task.length - 1)) || [];
+ // prevent dead-locks
+ var len = requires.length;
+ var dep;
+ while (len--) {
+ if (!(dep = tasks[requires[len]])) {
+ throw new Error('Has inexistant dependency');
+ }
+ if (_isArray(dep) && !!~dep.indexOf(k)) {
+ throw new Error('Has cyclic dependencies');
+ }
+ }
var ready = function () {
return _reduce(requires, function (a, x) {
return (a && results.hasOwnProperty(x));
@@ -530,7 +666,7 @@
};
async.waterfall = function (tasks, callback) {
- callback = callback || function () {};
+ callback = callback || noop;
if (!_isArray(tasks)) {
var err = new Error('First argument to waterfall must be an array of functions');
return callback(err);
@@ -542,7 +678,7 @@
return function (err) {
if (err) {
callback.apply(null, arguments);
- callback = function () {};
+ callback = noop;
}
else {
var args = Array.prototype.slice.call(arguments, 1);
@@ -563,7 +699,7 @@
};
var _parallel = function(eachfn, tasks, callback) {
- callback = callback || function () {};
+ callback = callback || noop;
if (_isArray(tasks)) {
eachfn.map(tasks, function (fn, callback) {
if (fn) {
@@ -603,7 +739,7 @@
};
async.series = function (tasks, callback) {
- callback = callback || function () {};
+ callback = callback || noop;
if (_isArray(tasks)) {
async.mapSeries(tasks, function (fn, callback) {
if (fn) {
diff --git a/package.json b/package.json
index 09f76aa..1424c76 100644
--- a/package.json
+++ b/package.json
@@ -1,36 +1,54 @@
{
- "name": "async",
- "description": "Higher-order functions and common patterns for asynchronous code",
- "main": "./lib/async",
- "author": "Caolan McMahon",
- "version": "0.9.0",
- "repository" : {
- "type" : "git",
- "url" : "https://github.com/caolan/async.git"
- },
- "bugs" : {
- "url" : "https://github.com/caolan/async/issues"
- },
- "licenses" : [
- {
- "type" : "MIT",
- "url" : "https://github.com/caolan/async/raw/master/LICENSE"
- }
+ "name": "async",
+ "description": "Higher-order functions and common patterns for asynchronous code",
+ "main": "lib/async.js",
+ "author": "Caolan McMahon",
+ "version": "0.9.2",
+ "keywords": [
+ "async",
+ "callback",
+ "utility",
+ "module"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/caolan/async.git"
+ },
+ "bugs": {
+ "url": "https://github.com/caolan/async/issues"
+ },
+ "license": "MIT",
+ "devDependencies": {
+ "nodeunit": ">0.0.0",
+ "uglify-js": "1.2.x",
+ "nodelint": ">0.0.0",
+ "lodash": ">=2.4.1"
+ },
+ "jam": {
+ "main": "lib/async.js",
+ "include": [
+ "lib/async.js",
+ "README.md",
+ "LICENSE"
],
- "devDependencies": {
- "nodeunit": ">0.0.0",
- "uglify-js": "1.2.x",
- "nodelint": ">0.0.0"
- },
- "jam": {
- "main": "lib/async.js",
- "include": [
- "lib/async.js",
- "README.md",
- "LICENSE"
- ]
- },
- "scripts": {
- "test": "nodeunit test/test-async.js"
- }
-}
+ "categories": [
+ "Utilities"
+ ]
+ },
+ "scripts": {
+ "test": "nodeunit test/test-async.js"
+ },
+ "spm": {
+ "main": "lib/async.js"
+ },
+ "volo": {
+ "main": "lib/async.js",
+ "ignore": [
+ "**/.*",
+ "node_modules",
+ "bower_components",
+ "test",
+ "tests"
+ ]
+ }
+} \ No newline at end of file
diff --git a/support/sync-package-managers.js b/support/sync-package-managers.js
new file mode 100755
index 0000000..30cb7c2
--- /dev/null
+++ b/support/sync-package-managers.js
@@ -0,0 +1,53 @@
+#!/usr/bin/env node
+
+// This should probably be its own module but complaints about bower/etc.
+// support keep coming up and I'd rather just enable the workflow here for now
+// and figure out where this should live later. -- @beaugunderson
+
+var fs = require('fs');
+var _ = require('lodash');
+
+var packageJson = require('../package.json');
+
+var IGNORES = ['**/.*', 'node_modules', 'bower_components', 'test', 'tests'];
+var INCLUDES = ['lib/async.js', 'README.md', 'LICENSE'];
+var REPOSITORY_NAME = 'caolan/async';
+
+packageJson.jam = {
+ main: packageJson.main,
+ include: INCLUDES,
+ categories: ['Utilities']
+};
+
+packageJson.spm = {
+ main: packageJson.main
+};
+
+packageJson.volo = {
+ main: packageJson.main,
+ ignore: IGNORES
+};
+
+var bowerSpecific = {
+ moduleType: ['amd', 'globals', 'node'],
+ ignore: IGNORES,
+ authors: [packageJson.author]
+};
+
+var bowerInclude = ['name', 'description', 'version', 'main', 'keywords',
+ 'license', 'homepage', 'repository', 'devDependencies'];
+
+var componentSpecific = {
+ repository: REPOSITORY_NAME,
+ scripts: [packageJson.main]
+};
+
+var componentInclude = ['name', 'description', 'version', 'keywords',
+ 'license'];
+
+var bowerJson = _.merge({}, _.pick(packageJson, bowerInclude), bowerSpecific);
+var componentJson = _.merge({}, _.pick(packageJson, componentInclude), componentSpecific);
+
+fs.writeFileSync('./bower.json', JSON.stringify(bowerJson, null, 2));
+fs.writeFileSync('./component.json', JSON.stringify(componentJson, null, 2));
+fs.writeFileSync('./package.json', JSON.stringify(packageJson, null, 2));
diff --git a/test/test-async.js b/test/test-async.js
index 6a35606..e660c1b 100755
--- a/test/test-async.js
+++ b/test/test-async.js
@@ -17,6 +17,13 @@ function eachIterator(args, x, callback) {
}, x*25);
}
+function forEachOfIterator(args, value, key, callback) {
+ setTimeout(function(){
+ args.push(key, value);
+ callback();
+ }, value*25);
+}
+
function mapIterator(call_order, x, callback) {
setTimeout(function(){
call_order.push(x);
@@ -43,6 +50,13 @@ function eachNoCallbackIterator(test, x, callback) {
test.done();
}
+function forEachOfNoCallbackIterator(test, x, key, callback) {
+ test.equal(x, 1);
+ test.equal(key, "a");
+ callback();
+ test.done();
+}
+
function getFunctionsObject(call_order) {
return {
one: function(callback){
@@ -580,6 +594,33 @@ exports['auto modifying results causes final callback to run early'] = function(
});
};
+// Issue 263 on github: https://github.com/caolan/async/issues/263
+exports['auto prevent dead-locks due to inexistant dependencies'] = function(test) {
+ test.throws(function () {
+ async.auto({
+ task1: ['noexist', function(callback, results){
+ callback(null, 'task1');
+ }]
+ });
+ }, Error);
+ test.done();
+};
+
+// Issue 263 on github: https://github.com/caolan/async/issues/263
+exports['auto prevent dead-locks due to cyclic dependencies'] = function(test) {
+ test.throws(function () {
+ async.auto({
+ task1: ['task2', function(callback, results){
+ callback(null, 'task1');
+ }],
+ task2: ['task1', function(callback, results){
+ callback(null, 'task2');
+ }]
+ });
+ }, Error);
+ test.done();
+};
+
// Issue 306 on github: https://github.com/caolan/async/issues/306
exports['retry when attempt succeeds'] = function(test) {
var failed = 3
@@ -619,7 +660,7 @@ exports['retry as an embedded task'] = function(test) {
var retryResult = 'RETRY';
var fooResults;
var retryResults;
-
+
async.auto({
foo: function(callback, results){
fooResults = results;
@@ -1165,6 +1206,47 @@ exports['forEach alias'] = function (test) {
test.done();
};
+exports['forEachOf'] = function(test){
+ var args = [];
+ async.forEachOf({ a: 1, b: 2 }, forEachOfIterator.bind(this, args), function(err){
+ test.same(args, ["a", 1, "b", 2]);
+ test.done();
+ });
+};
+
+exports['forEachOf empty object'] = function(test){
+ test.expect(1);
+ async.forEachOf({}, function(value, key, callback){
+ test.ok(false, 'iterator should not be called');
+ callback();
+ }, function(err) {
+ test.ok(true, 'should call callback');
+ });
+ setTimeout(test.done, 25);
+};
+
+exports['forEachOf error'] = function(test){
+ test.expect(1);
+ async.forEachOf({ a: 1, b: 2 }, function(value, key, callback) {
+ callback('error');
+ }, function(err){
+ test.equals(err, 'error');
+ });
+ setTimeout(test.done, 50);
+};
+
+exports['forEachOf no callback'] = function(test){
+ async.forEachOf({ a: 1 }, forEachOfNoCallbackIterator.bind(this, test));
+};
+
+exports['forEachOf with array'] = function(test){
+ var args = [];
+ async.forEachOf([ "a", "b" ], forEachOfIterator.bind(this, args), function(err){
+ test.same(args, [0, "a", 1, "b"]);
+ test.done();
+ });
+};
+
exports['eachSeries'] = function(test){
var args = [];
async.eachSeries([1,3,2], eachIterator.bind(this, args), function(err){
@@ -1201,10 +1283,6 @@ exports['eachSeries no callback'] = function(test){
async.eachSeries([1], eachNoCallbackIterator.bind(this, test));
};
-exports['forEachSeries alias'] = function (test) {
- test.strictEqual(async.eachSeries, async.forEachSeries);
- test.done();
-};
exports['eachLimit'] = function(test){
var args = [];
@@ -1293,11 +1371,153 @@ exports['eachLimit synchronous'] = function(test){
});
};
+exports['forEachSeries alias'] = function (test) {
+ test.strictEqual(async.eachSeries, async.forEachSeries);
+ test.done();
+};
+
+exports['forEachOfSeries'] = function(test){
+ var args = [];
+ async.forEachOfSeries({ a: 1, b: 2 }, forEachOfIterator.bind(this, args), function(err){
+ test.same(args, [ "a", 1, "b", 2 ]);
+ test.done();
+ });
+};
+
+exports['forEachOfSeries empty object'] = function(test){
+ test.expect(1);
+ async.forEachOfSeries({}, function(x, callback){
+ test.ok(false, 'iterator should not be called');
+ callback();
+ }, function(err){
+ test.ok(true, 'should call callback');
+ });
+ setTimeout(test.done, 25);
+};
+
+exports['forEachOfSeries error'] = function(test){
+ test.expect(2);
+ var call_order = [];
+ async.forEachOfSeries({ a: 1, b: 2 }, function(value, key, callback){
+ call_order.push(value, key);
+ callback('error');
+ }, function(err){
+ test.same(call_order, [ 1, "a" ]);
+ test.equals(err, 'error');
+ });
+ setTimeout(test.done, 50);
+};
+
+exports['forEachOfSeries no callback'] = function(test){
+ async.forEachOfSeries({ a: 1 }, forEachOfNoCallbackIterator.bind(this, test));
+};
+
+exports['forEachOfSeries with array'] = function(test){
+ var args = [];
+ async.forEachOfSeries([ "a", "b" ], forEachOfIterator.bind(this, args), function(err){
+ test.same(args, [ 0, "a", 1, "b" ]);
+ test.done();
+ });
+};
+
exports['forEachLimit alias'] = function (test) {
test.strictEqual(async.eachLimit, async.forEachLimit);
test.done();
};
+exports['forEachOfLimit'] = function(test){
+ var args = [];
+ var obj = { a: 1, b: 2, c: 3, d: 4 };
+ async.forEachOfLimit(obj, 2, function(value, key, callback){
+ setTimeout(function(){
+ args.push(value, key);
+ callback();
+ }, value * 5);
+ }, function(err){
+ test.same(args, [ 1, "a", 2, "b", 3, "c", 4, "d" ]);
+ test.done();
+ });
+};
+
+exports['forEachOfLimit empty object'] = function(test){
+ test.expect(1);
+ async.forEachOfLimit({}, 2, function(value, key, callback){
+ test.ok(false, 'iterator should not be called');
+ callback();
+ }, function(err){
+ test.ok(true, 'should call callback');
+ });
+ setTimeout(test.done, 25);
+};
+
+exports['forEachOfLimit limit exceeds size'] = function(test){
+ var args = [];
+ var obj = { a: 1, b: 2, c: 3, d: 4, e: 5 };
+ async.forEachOfLimit(obj, 10, forEachOfIterator.bind(this, args), function(err){
+ test.same(args, [ "a", 1, "b", 2, "c", 3, "d", 4, "e", 5 ]);
+ test.done();
+ });
+};
+
+exports['forEachOfLimit limit equal size'] = function(test){
+ var args = [];
+ var obj = { a: 1, b: 2, c: 3, d: 4, e: 5 };
+ async.forEachOfLimit(obj, 5, forEachOfIterator.bind(this, args), function(err){
+ test.same(args, [ "a", 1, "b", 2, "c", 3, "d", 4, "e", 5 ]);
+ test.done();
+ });
+};
+
+exports['forEachOfLimit zero limit'] = function(test){
+ test.expect(1);
+ async.forEachOfLimit({ a: 1, b: 2 }, 0, function(x, callback){
+ test.ok(false, 'iterator should not be called');
+ callback();
+ }, function(err){
+ test.ok(true, 'should call callback');
+ });
+ setTimeout(test.done, 25);
+};
+
+exports['forEachOfLimit error'] = function(test){
+ test.expect(2);
+ var obj = { a: 1, b: 2, c: 3, d: 4, e: 5 };
+ var call_order = [];
+
+ async.forEachOfLimit(obj, 3, function(value, key, callback){
+ call_order.push(value, key);
+ if (value === 2) {
+ callback('error');
+ }
+ }, function(err){
+ test.same(call_order, [ 1, "a", 2, "b" ]);
+ test.equals(err, 'error');
+ });
+ setTimeout(test.done, 25);
+};
+
+exports['forEachOfLimit no callback'] = function(test){
+ async.forEachOfLimit({ a: 1 }, 1, forEachOfNoCallbackIterator.bind(this, test));
+};
+
+exports['forEachOfLimit synchronous'] = function(test){
+ var args = [];
+ var obj = { a: 1, b: 2 };
+ async.forEachOfLimit(obj, 5, forEachOfIterator.bind(this, args), function(err){
+ test.same(args, [ "a", 1, "b", 2 ]);
+ test.done();
+ });
+};
+
+exports['forEachOfLimit with array'] = function(test){
+ var args = [];
+ var arr = [ "a", "b" ]
+ async.forEachOfLimit(arr, 1, forEachOfIterator.bind(this, args), function (err) {
+ test.same(args, [ 0, "a", 1, "b" ]);
+ test.done();
+ });
+};
+
exports['map'] = function(test){
var call_order = [];
async.map([1,3,2], mapIterator.bind(this, call_order), function(err, results){
@@ -1882,15 +2102,13 @@ exports['noConflict - node only'] = function(test){
// node only test
test.expect(3);
var fs = require('fs');
+ var vm = require('vm');
var filename = __dirname + '/../lib/async.js';
fs.readFile(filename, function(err, content){
if(err) return test.done();
- // Script -> NodeScript in node v0.6.x
- var Script = process.binding('evals').Script || process.binding('evals').NodeScript;
-
- var s = new Script(content, filename);
- var s2 = new Script(
+ var s = vm.createScript(content, filename);
+ var s2 = vm.createScript(
content + 'this.async2 = this.async.noConflict();',
filename
);
@@ -1996,7 +2214,6 @@ exports['doUntil'] = function (test) {
var count = 0;
async.doUntil(
function (cb) {
- debugger
call_order.push(['iterator', count]);
count++;
cb();
@@ -2024,7 +2241,6 @@ exports['doUntil callback params'] = function (test) {
var count = 0;
async.doUntil(
function (cb) {
- debugger
call_order.push(['iterator', count]);
count++;
cb(null, count);
@@ -2091,7 +2307,6 @@ exports['doWhilst'] = function (test) {
return (count < 5);
},
function (err) {
- debugger
test.same(call_order, [
['iterator', 0], ['test', 1],
['iterator', 1], ['test', 2],
@@ -2120,7 +2335,6 @@ exports['doWhilst callback params'] = function (test) {
return (c < 5);
},
function (err) {
- debugger
test.same(call_order, [
['iterator', 0], ['test', 1],
['iterator', 1], ['test', 2],
@@ -2459,8 +2673,10 @@ exports['queue pause'] = function(test) {
tasks = [ 1, 2, 3, 4, 5, 6 ],
elapsed = (function () {
- var start = +Date.now();
- return function () { return Math.floor((+Date.now() - start) / 100) * 100; };
+ var start = (new Date()).valueOf();
+ return function () {
+ return Math.round(((new Date()).valueOf() - start) / 100) * 100;
+ };
})();
var q = async.queue(function (task, callback) {
@@ -2510,8 +2726,10 @@ exports['queue pause with concurrency'] = function(test) {
tasks = [ 1, 2, 3, 4, 5, 6 ],
elapsed = (function () {
- var start = +Date.now();
- return function () { return Math.floor((+Date.now() - start) / 100) * 100; };
+ var start = (new Date()).valueOf();
+ return function () {
+ return Math.round(((new Date()).valueOf() - start) / 100) * 100;
+ };
})();
var q = async.queue(function (task, callback) {
@@ -2808,20 +3026,20 @@ exports['cargo bulk task'] = function (test) {
};
exports['cargo drain once'] = function (test) {
-
+
var c = async.cargo(function (tasks, callback) {
callback();
}, 3);
-
+
var drainCounter = 0;
c.drain = function () {
drainCounter++;
}
-
+
for(var i = 0; i < 10; i++){
c.push(i);
}
-
+
setTimeout(function(){
test.equal(drainCounter, 1);
test.done();
@@ -2829,17 +3047,17 @@ exports['cargo drain once'] = function (test) {
};
exports['cargo drain twice'] = function (test) {
-
+
var c = async.cargo(function (tasks, callback) {
callback();
}, 3);
-
+
var loadCargo = function(){
for(var i = 0; i < 10; i++){
c.push(i);
}
};
-
+
var drainCounter = 0;
c.drain = function () {
drainCounter++;
@@ -3163,7 +3381,7 @@ exports['queue started'] = function(test) {
var calls = [];
var q = async.queue(function(task, cb) {});
-
+
test.equal(q.started, false);
q.push([]);
test.equal(q.started, true);