summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md74
-rwxr-xr-xlib/async.js19
-rw-r--r--package.json2
-rwxr-xr-xtest/test-async.js60
4 files changed, 150 insertions, 5 deletions
diff --git a/README.md b/README.md
index 6a9fb0b..0e16fba 100644
--- a/README.md
+++ b/README.md
@@ -38,6 +38,41 @@ There are many more functions available so take a look at the docs below for a
full list. This module aims to be comprehensive, so if you feel anything is
missing please create a GitHub issue for it.
+## Common Pitfalls
+
+### Binding a context to an iterator
+
+This section is really about bind, not about async. If you are wondering how to
+make async execute your iterators in a given context, or are confused as to why
+a method of another library isn't working as an iterator, study this example:
+
+```js
+// Here is a simple object with an (unnecessarily roundabout) squaring method
+var AsyncSquaringLibrary = {
+ squareExponent: 2,
+ square: function(number, callback){
+ var result = Math.pow(number, this.squareExponent);
+ setTimeout(function(){
+ callback(null, result);
+ }, 200);
+ }
+};
+
+async.map([1, 2, 3], AsyncSquaringLibrary.square, function(err, result){
+ // result is [NaN, NaN, NaN]
+ // This fails because the `this.squareExponent` expression in the square
+ // function is not evaluated in the context of AsyncSquaringLibrary, and is
+ // therefore undefined.
+});
+
+async.map([1, 2, 3], AsyncSquaringLibrary.square.bind(AsyncSquaringLibrary), function(err, result){
+ // result is [1, 4, 9]
+ // With the help of bind we can attach a context to the iterator before
+ // passing it to async. Now the square function will be executed in its
+ // 'home' AsyncSquaringLibrary context and the value of `this.squareExponent`
+ // will be as expected.
+});
+```
## Download
@@ -55,7 +90,7 @@ __Production:__ [async.min.js](https://github.com/caolan/async/raw/master/dist/a
## In the Browser
-So far its been tested in IE6, IE7, IE8, FF3.6 and Chrome 5. Usage:
+So far it's been tested in IE6, IE7, IE8, FF3.6 and Chrome 5. Usage:
```html
<script type="text/javascript" src="async.js"></script>
@@ -93,6 +128,7 @@ So far its been tested in IE6, IE7, IE8, FF3.6 and Chrome 5. Usage:
* [doUntil](#doUntil)
* [waterfall](#waterfall)
* [compose](#compose)
+* [applyEach](#applyEach)
* [queue](#queue)
* [cargo](#cargo)
* [auto](#auto)
@@ -338,7 +374,7 @@ function only operates in series. For performance reasons, it may make sense to
split a call to this function into a parallel map, then use the normal
Array.prototype.reduce on the results. This function is for situations where
each step in the reduction needs to be async, if you can get the data before
-reducing it then its probably a good idea to do so.
+reducing it then it's probably a good idea to do so.
__Arguments__
@@ -833,6 +869,36 @@ add1mul3(4, function (err, result) {
```
---------------------------------------
+<a name="applyEach" />
+### applyEach(fns, args..., callback)
+
+Applies the provided arguments to each function in the array, calling the
+callback after all functions have completed. If you only provide the first
+argument then it will return a function which lets you pass in the
+arguments as if it were a single function call.
+
+__Arguments__
+
+* fns - the asynchronous functions to all call with the same arguments
+* args... - any number of separate arguments to pass to the function
+* callback - the final argument should be the callback, called when all
+ functions have completed processing
+
+
+__Example__
+
+```js
+async.applyEach([enableSearch, updateSchema], 'bucket', callback);
+
+// partial application example:
+async.each(
+ buckets,
+ async.applyEach([enableSearch, updateSchema]),
+ callback
+);
+```
+
+---------------------------------------
<a name="queue" />
### queue(worker, concurrency)
@@ -921,7 +987,7 @@ __Arguments__
tasks, which must call its callback(err) argument when finished, with an
optional error as an argument.
* payload - An optional integer for determining how many tasks should be
- process per round, default is unlimited.
+ processed per round; if omitted, the default is unlimited.
__Cargo objects__
@@ -1079,7 +1145,7 @@ new tasks much easier and makes the code more readable.
### iterator(tasks)
Creates an iterator function which calls the next function in the array,
-returning a continuation to call the next one after that. Its also possible to
+returning a continuation to call the next one after that. It's also possible to
'peek' the next iterator by doing iterator.next().
This function is used internally by the async module but can be useful when
diff --git a/lib/async.js b/lib/async.js
index 2ec1934..5747dbd 100755
--- a/lib/async.js
+++ b/lib/async.js
@@ -949,6 +949,25 @@
};
};
+ async.applyEach = function (fns /*args...*/) {
+ var go = function () {
+ var that = this;
+ var args = Array.prototype.slice.call(arguments);
+ var callback = args.pop();
+ return async.each(fns, function (fn, cb) {
+ fn.apply(that, args.concat([cb]));
+ },
+ callback);
+ };
+ if (arguments.length > 1) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ return go.apply(this, args);
+ }
+ else {
+ return go;
+ }
+ };
+
// AMD / RequireJS
if (typeof define !== 'undefined' && define.amd) {
define([], function () {
diff --git a/package.json b/package.json
index 9d89522..9fa85b5 100644
--- a/package.json
+++ b/package.json
@@ -3,7 +3,7 @@
"description": "Higher-order functions and common patterns for asynchronous code",
"main": "./lib/async",
"author": "Caolan McMahon",
- "version": "0.2.5",
+ "version": "0.2.6",
"repository" : {
"type" : "git",
"url" : "http://github.com/caolan/async.git"
diff --git a/test/test-async.js b/test/test-async.js
index 62e0643..1f0564f 100755
--- a/test/test-async.js
+++ b/test/test-async.js
@@ -66,6 +66,66 @@ function getFunctionsObject(call_order) {
};
}
+exports['applyEach'] = function (test) {
+ test.expect(4);
+ var call_order = [];
+ var one = function (val, cb) {
+ test.equal(val, 5);
+ setTimeout(function () {
+ call_order.push('one');
+ cb(null, 1);
+ }, 100);
+ };
+ var two = function (val, cb) {
+ test.equal(val, 5);
+ setTimeout(function () {
+ call_order.push('two');
+ cb(null, 2);
+ }, 50);
+ };
+ var three = function (val, cb) {
+ test.equal(val, 5);
+ setTimeout(function () {
+ call_order.push('three');
+ cb(null, 3);
+ }, 150);
+ };
+ async.applyEach([one, two, three], 5, function (err) {
+ test.same(call_order, ['two', 'one', 'three']);
+ test.done();
+ });
+};
+
+exports['applyEach partial application'] = function (test) {
+ test.expect(4);
+ var call_order = [];
+ var one = function (val, cb) {
+ test.equal(val, 5);
+ setTimeout(function () {
+ call_order.push('one');
+ cb(null, 1);
+ }, 100);
+ };
+ var two = function (val, cb) {
+ test.equal(val, 5);
+ setTimeout(function () {
+ call_order.push('two');
+ cb(null, 2);
+ }, 50);
+ };
+ var three = function (val, cb) {
+ test.equal(val, 5);
+ setTimeout(function () {
+ call_order.push('three');
+ cb(null, 3);
+ }, 150);
+ };
+ async.applyEach([one, two, three])(5, function (err) {
+ test.same(call_order, ['two', 'one', 'three']);
+ test.done();
+ });
+};
+
exports['compose'] = function (test) {
test.expect(4);
var add2 = function (n, cb) {