Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

added demo files

  • Loading branch information...
commit 6df6fc1c9a68a6a3ad7a5010e66372506b7aeb6c 1 parent f4b5a8e
therealplato authored
7 README.md
Source Rendered
... ... @@ -1,4 +1,9 @@
1 1 node-async-demo
2 2 ===============
3 3
4   -Demo of invoking and handling data with async.series, .parallel, .waterfall
  4 +Demo of invoking and handling data with async.series, .parallel, .waterfall
  5 +
  6 +async is packaged in node_modules/
  7 +
  8 +Simply run:
  9 + node dbasync.js
184 dbasync.js
... ... @@ -0,0 +1,184 @@
  1 +var async = require('async');
  2 +
  3 +// defaultInit() is called at EOF. we use async.series/waterfall/parallel
  4 +// to perform different steps of a database initialization in order
  5 +
  6 +initDefault = function() {
  7 +// We set up an async.series function that looks like .series([fn1,fn2...],cb);
  8 +// They will be called sequentially. cb is passed an ordered results array.
  9 + console.log('We will call four functions in order using async.series:');
  10 + console.log(' test_connection : one async fn');
  11 + console.log(' destroy_whole_db : three fns in a waterfall');
  12 + console.log(' create_new_db : three fns in parallel');
  13 + console.log(' reset_design_docs : three fns in series');
  14 + async.series(
  15 + [
  16 + //this is an array of functions - the first argument of async.series
  17 + //inside these we are calling asynchronous test_connection(cb); etc
  18 + function(fn) { test_connection(function(err, results) {
  19 + //fn is the callback to move to the next async.* function.
  20 + if (!err){fn(null,results)} else {fn(err)};
  21 + });
  22 + },
  23 + function(fn) { destroy_whole_db(function(err, results) {
  24 + if (!err){fn(null,results)} else {fn(err)};
  25 + });
  26 + },
  27 + function(fn) { create_new_db(function(err, results) {
  28 + if (!err){fn(null,results)} else {fn(err)};
  29 + });
  30 + },
  31 + function(fn) { reset_design_docs(function(err, results) {
  32 + if (!err){fn(null,results)} else {fn(err)};
  33 + });
  34 + },],
  35 + function(err, results) {
  36 + //this is called when the last fn in the above array callsback fn(_)
  37 + if(!err) {
  38 + console.log('\nSuccess! Results were:');
  39 + console.log(' test_connection :\n'+results[0]);
  40 + console.log(' destroy_whole_db :\n'+JSON.stringify(results[1]));
  41 + console.log(' create_new_db :\n'+results[2]);
  42 + console.log(' reset_design_docs :\n'+results[3]);
  43 + }
  44 + else {console.log('Error in async demo!\n'+err)};
  45 + } // end of async.series callback declaration
  46 + ); // end of async.series(); call
  47 +}; // end of defaultInit() declaration
  48 +
  49 +// Functions:
  50 +// Here we will define a few functions to call above
  51 +// All take a callback argument and call callback(null, results) upon success
  52 +//
  53 +// test_connection Single 2 second timeout,
  54 +// destroy_whole_db 3 functions in an async waterfall
  55 +// create_new_db 3 functions in an async parallel
  56 +// reset_design_docs 3 functions in an async series
  57 +
  58 +//
  59 +// test_connection
  60 +//
  61 +test_connection = function(callback) {
  62 + console.log('\ntest_connection called: one async function');
  63 + setTimeout(function() {
  64 + console.log(' test_connection done after 2s');
  65 + callback(null, "tc_ok");
  66 + }, 2000);
  67 +};
  68 +
  69 +//
  70 +// destroy_whole_db
  71 +//
  72 +destroy_whole_db = function(callback) {
  73 + console.log('\ndestroy_whole_db called: one async.waterfall');
  74 + async.waterfall(
  75 + [
  76 + function(fn){
  77 + start=new Date().toJSON();
  78 + console.log(' '+start+' - destroy_whole_db fn1 called')
  79 + fn(null, start);
  80 + },
  81 + function(start, fn){
  82 + console.log(' fn2 passed '+start+' by fn1');
  83 + setTimeout(function(){
  84 + startD = new Date(start);
  85 + now1=new Date();
  86 + deltams=now1.getTime() - startD.getTime();
  87 + console.log(' destroy_whole_db fn2 calling back to fn3; elapsed time: '
  88 + +deltams+' ms');
  89 + fn(null, start, now1.toJSON());
  90 + }, 2000);
  91 + },
  92 + function(start, now1, fn) {
  93 + console.log(' fn3 passed '+start+' and '+now1);
  94 + setTimeout(function(){
  95 + now2=new Date().toJSON();
  96 + console.log(' fn3 calling final waterfall callback with start, now1, now2');
  97 + fn(null, start, now1, now2);
  98 + } , 1000)
  99 + }],
  100 + function(err, start, now1, now2) {
  101 + console.log(' we\'ve passed the results of each fn down the cascade '+
  102 + 'to this final callback:');
  103 + console.log(' start: '+start);
  104 + console.log(' now1 : '+now1);
  105 + console.log(' now2 : '+now2);
  106 + console.log(' now : '+(new Date()).toJSON());
  107 + callback(null, {t0:start, t1: now1, t2: now2});
  108 + }); //end of async.waterfall( [fn1...] , cb(){} );
  109 +};
  110 +
  111 +
  112 +//
  113 +// create_new_db
  114 +//
  115 +create_new_db = function(callback) {
  116 + console.log('\ncreate_new_db called: one async.parallel chain');
  117 + async.parallel(
  118 + [ function(fn){
  119 + console.log(' in async.parallel fn1');
  120 + setTimeout(function() {
  121 + console.log(' async.parallel fn1 done after 2.1s');
  122 + fn(null, "cndb.fn1_ok");
  123 + }, 2100);
  124 + },function(fn){
  125 + console.log(' in async.parallel fn2');
  126 + setTimeout(function() {
  127 + console.log(' async.parallel fn2 done after 2.3s');
  128 + fn(null, "cndb.fn2_ok");
  129 + }, 2300);
  130 + },function(fn){
  131 + console.log(' in async.parallel fn3');
  132 + setTimeout(function() {
  133 + console.log(' async.parallel fn3 done after 1.5s');
  134 + fn(null, "cndb.fn3_ok");
  135 + }, 1500);
  136 + } ],
  137 + function(err, results) {
  138 + console.log(' reached final callback to async.parallel() in create_new_db ');
  139 + console.log(' passing async.parallel\'s results to create_new_db\'s callback');
  140 + console.log(' Look, results is ordered properly:\n'+results);
  141 + callback(null, results);
  142 + } ); //end of async.parallel([fn1,fn2],cb);
  143 +}; //end of create_new_db declaration
  144 +
  145 +//
  146 +// reset_design_docs
  147 +//
  148 +reset_design_docs = function(callback) {
  149 + console.log('\nreset_design_docs called, starting an async.series');
  150 + async.series(
  151 + [
  152 + function(fn) {
  153 + console.log(' reset_design_docs: async.series fn1 called');
  154 + fn(null, "rdd.fn1_ok");
  155 + } , //next function in series' array!
  156 + function(fn) {
  157 + console.log(' reset_design_docs: async.series fn2 called');
  158 + setTimeout(function(){
  159 + console.log(' reset_design_docs: fn2 done after 3s');
  160 + fn(null,"rdd.fn2_ok");
  161 + }, 3000);
  162 + }
  163 + ], // async.series() 2nd arg is a final callback
  164 + function(err, resultsArr) {
  165 + if(!err) { // the series had no errors, signal whatever called
  166 + console.log(' final callback of reset_design_docs async.series chain');
  167 + console.log(' calling back to whatever called reset_design_docs...');
  168 + callback(null, resultsArr); // we're calling the cb passed into reset_design_docs
  169 + } else {
  170 + console.log('there was a problem in reset_design_docs:\n'+err);
  171 + callback(err);
  172 + };
  173 + } // end of async.series' callback
  174 + ); // finish calling async.series([fns],cb);
  175 +}; // end of function reset_design_docs(callback) {...};
  176 +
  177 +
  178 +//
  179 +//// Fire it up!
  180 +//
  181 +
  182 +initDefault();
  183 +
  184 +
9 node_modules/async/.gitmodules
... ... @@ -0,0 +1,9 @@
  1 +[submodule "deps/nodeunit"]
  2 + path = deps/nodeunit
  3 + url = git://github.com/caolan/nodeunit.git
  4 +[submodule "deps/UglifyJS"]
  5 + path = deps/UglifyJS
  6 + url = https://github.com/mishoo/UglifyJS.git
  7 +[submodule "deps/nodelint"]
  8 + path = deps/nodelint
  9 + url = https://github.com/tav/nodelint.git
4 node_modules/async/.npmignore
... ... @@ -0,0 +1,4 @@
  1 +deps
  2 +dist
  3 +test
  4 +nodelint.cfg
19 node_modules/async/LICENSE
... ... @@ -0,0 +1,19 @@
  1 +Copyright (c) 2010 Caolan McMahon
  2 +
  3 +Permission is hereby granted, free of charge, to any person obtaining a copy
  4 +of this software and associated documentation files (the "Software"), to deal
  5 +in the Software without restriction, including without limitation the rights
  6 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7 +copies of the Software, and to permit persons to whom the Software is
  8 +furnished to do so, subject to the following conditions:
  9 +
  10 +The above copyright notice and this permission notice shall be included in
  11 +all copies or substantial portions of the Software.
  12 +
  13 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19 +THE SOFTWARE.
25 node_modules/async/Makefile
... ... @@ -0,0 +1,25 @@
  1 +PACKAGE = asyncjs
  2 +NODEJS = $(if $(shell test -f /usr/bin/nodejs && echo "true"),nodejs,node)
  3 +CWD := $(shell pwd)
  4 +NODEUNIT = $(CWD)/node_modules/nodeunit/bin/nodeunit
  5 +UGLIFY = $(CWD)/node_modules/uglify-js/bin/uglifyjs
  6 +NODELINT = $(CWD)/node_modules/nodelint/nodelint
  7 +
  8 +BUILDDIR = dist
  9 +
  10 +all: clean test build
  11 +
  12 +build: $(wildcard lib/*.js)
  13 + mkdir -p $(BUILDDIR)
  14 + $(UGLIFY) lib/async.js > $(BUILDDIR)/async.min.js
  15 +
  16 +test:
  17 + $(NODEUNIT) test
  18 +
  19 +clean:
  20 + rm -rf $(BUILDDIR)
  21 +
  22 +lint:
  23 + $(NODELINT) --config nodelint.cfg lib/async.js
  24 +
  25 +.PHONY: test build all
1,022 node_modules/async/README.md
Source Rendered
... ... @@ -0,0 +1,1022 @@
  1 +# Async.js
  2 +
  3 +Async is a utility module which provides straight-forward, powerful functions
  4 +for working with asynchronous JavaScript. Although originally designed for
  5 +use with [node.js](http://nodejs.org), it can also be used directly in the
  6 +browser.
  7 +
  8 +Async provides around 20 functions that include the usual 'functional'
  9 +suspects (map, reduce, filter, forEach…) as well as some common patterns
  10 +for asynchronous control flow (parallel, series, waterfall…). All these
  11 +functions assume you follow the node.js convention of providing a single
  12 +callback as the last argument of your async function.
  13 +
  14 +
  15 +## Quick Examples
  16 +
  17 + async.map(['file1','file2','file3'], fs.stat, function(err, results){
  18 + // results is now an array of stats for each file
  19 + });
  20 +
  21 + async.filter(['file1','file2','file3'], path.exists, function(results){
  22 + // results now equals an array of the existing files
  23 + });
  24 +
  25 + async.parallel([
  26 + function(){ ... },
  27 + function(){ ... }
  28 + ], callback);
  29 +
  30 + async.series([
  31 + function(){ ... },
  32 + function(){ ... }
  33 + ]);
  34 +
  35 +There are many more functions available so take a look at the docs below for a
  36 +full list. This module aims to be comprehensive, so if you feel anything is
  37 +missing please create a GitHub issue for it.
  38 +
  39 +
  40 +## Download
  41 +
  42 +Releases are available for download from
  43 +[GitHub](http://github.com/caolan/async/downloads).
  44 +Alternatively, you can install using Node Package Manager (npm):
  45 +
  46 + npm install async
  47 +
  48 +
  49 +__Development:__ [async.js](https://github.com/caolan/async/raw/master/lib/async.js) - 17.5kb Uncompressed
  50 +
  51 +__Production:__ [async.min.js](https://github.com/caolan/async/raw/master/dist/async.min.js) - 1.7kb Packed and Gzipped
  52 +
  53 +
  54 +## In the Browser
  55 +
  56 +So far its been tested in IE6, IE7, IE8, FF3.6 and Chrome 5. Usage:
  57 +
  58 + <script type="text/javascript" src="async.js"></script>
  59 + <script type="text/javascript">
  60 +
  61 + async.map(data, asyncProcess, function(err, results){
  62 + alert(results);
  63 + });
  64 +
  65 + </script>
  66 +
  67 +
  68 +## Documentation
  69 +
  70 +### Collections
  71 +
  72 +* [forEach](#forEach)
  73 +* [map](#map)
  74 +* [filter](#filter)
  75 +* [reject](#reject)
  76 +* [reduce](#reduce)
  77 +* [detect](#detect)
  78 +* [sortBy](#sortBy)
  79 +* [some](#some)
  80 +* [every](#every)
  81 +* [concat](#concat)
  82 +
  83 +### Control Flow
  84 +
  85 +* [series](#series)
  86 +* [parallel](#parallel)
  87 +* [whilst](#whilst)
  88 +* [until](#until)
  89 +* [waterfall](#waterfall)
  90 +* [queue](#queue)
  91 +* [auto](#auto)
  92 +* [iterator](#iterator)
  93 +* [apply](#apply)
  94 +* [nextTick](#nextTick)
  95 +
  96 +### Utils
  97 +
  98 +* [memoize](#memoize)
  99 +* [unmemoize](#unmemoize)
  100 +* [log](#log)
  101 +* [dir](#dir)
  102 +* [noConflict](#noConflict)
  103 +
  104 +
  105 +## Collections
  106 +
  107 +<a name="forEach" />
  108 +### forEach(arr, iterator, callback)
  109 +
  110 +Applies an iterator function to each item in an array, in parallel.
  111 +The iterator is called with an item from the list and a callback for when it
  112 +has finished. If the iterator passes an error to this callback, the main
  113 +callback for the forEach function is immediately called with the error.
  114 +
  115 +Note, that since this function applies the iterator to each item in parallel
  116 +there is no guarantee that the iterator functions will complete in order.
  117 +
  118 +__Arguments__
  119 +
  120 +* arr - An array to iterate over.
  121 +* iterator(item, callback) - A function to apply to each item in the array.
  122 + The iterator is passed a callback which must be called once it has completed.
  123 +* callback(err) - A callback which is called after all the iterator functions
  124 + have finished, or an error has occurred.
  125 +
  126 +__Example__
  127 +
  128 + // assuming openFiles is an array of file names and saveFile is a function
  129 + // to save the modified contents of that file:
  130 +
  131 + async.forEach(openFiles, saveFile, function(err){
  132 + // if any of the saves produced an error, err would equal that error
  133 + });
  134 +
  135 +---------------------------------------
  136 +
  137 +<a name="forEachSeries" />
  138 +### forEachSeries(arr, iterator, callback)
  139 +
  140 +The same as forEach only the iterator is applied to each item in the array in
  141 +series. The next iterator is only called once the current one has completed
  142 +processing. This means the iterator functions will complete in order.
  143 +
  144 +
  145 +---------------------------------------
  146 +
  147 +<a name="forEachLimit" />
  148 +### forEachLimit(arr, limit, iterator, callback)
  149 +
  150 +The same as forEach only the iterator is applied to batches of items in the
  151 +array, in series. The next batch of iterators is only called once the current
  152 +one has completed processing.
  153 +
  154 +__Arguments__
  155 +
  156 +* arr - An array to iterate over.
  157 +* limit - How many items should be in each batch.
  158 +* iterator(item, callback) - A function to apply to each item in the array.
  159 + The iterator is passed a callback which must be called once it has completed.
  160 +* callback(err) - A callback which is called after all the iterator functions
  161 + have finished, or an error has occurred.
  162 +
  163 +__Example__
  164 +
  165 + // Assume documents is an array of JSON objects and requestApi is a
  166 + // function that interacts with a rate-limited REST api.
  167 +
  168 + async.forEachLimit(documents, 20, requestApi, function(err){
  169 + // if any of the saves produced an error, err would equal that error
  170 + });
  171 +---------------------------------------
  172 +
  173 +<a name="map" />
  174 +### map(arr, iterator, callback)
  175 +
  176 +Produces a new array of values by mapping each value in the given array through
  177 +the iterator function. The iterator is called with an item from the array and a
  178 +callback for when it has finished processing. The callback takes 2 arguments,
  179 +an error and the transformed item from the array. If the iterator passes an
  180 +error to this callback, the main callback for the map function is immediately
  181 +called with the error.
  182 +
  183 +Note, that since this function applies the iterator to each item in parallel
  184 +there is no guarantee that the iterator functions will complete in order, however
  185 +the results array will be in the same order as the original array.
  186 +
  187 +__Arguments__
  188 +
  189 +* arr - An array to iterate over.
  190 +* iterator(item, callback) - A function to apply to each item in the array.
  191 + The iterator is passed a callback which must be called once it has completed
  192 + with an error (which can be null) and a transformed item.
  193 +* callback(err, results) - A callback which is called after all the iterator
  194 + functions have finished, or an error has occurred. Results is an array of the
  195 + transformed items from the original array.
  196 +
  197 +__Example__
  198 +
  199 + async.map(['file1','file2','file3'], fs.stat, function(err, results){
  200 + // results is now an array of stats for each file
  201 + });
  202 +
  203 +---------------------------------------
  204 +
  205 +<a name="mapSeries" />
  206 +### mapSeries(arr, iterator, callback)
  207 +
  208 +The same as map only the iterator is applied to each item in the array in
  209 +series. The next iterator is only called once the current one has completed
  210 +processing. The results array will be in the same order as the original.
  211 +
  212 +
  213 +---------------------------------------
  214 +
  215 +<a name="filter" />
  216 +### filter(arr, iterator, callback)
  217 +
  218 +__Alias:__ select
  219 +
  220 +Returns a new array of all the values which pass an async truth test.
  221 +_The callback for each iterator call only accepts a single argument of true or
  222 +false, it does not accept an error argument first!_ This is in-line with the
  223 +way node libraries work with truth tests like path.exists. This operation is
  224 +performed in parallel, but the results array will be in the same order as the
  225 +original.
  226 +
  227 +__Arguments__
  228 +
  229 +* arr - An array to iterate over.
  230 +* iterator(item, callback) - A truth test to apply to each item in the array.
  231 + The iterator is passed a callback which must be called once it has completed.
  232 +* callback(results) - A callback which is called after all the iterator
  233 + functions have finished.
  234 +
  235 +__Example__
  236 +
  237 + async.filter(['file1','file2','file3'], path.exists, function(results){
  238 + // results now equals an array of the existing files
  239 + });
  240 +
  241 +---------------------------------------
  242 +
  243 +<a name="filterSeries" />
  244 +### filterSeries(arr, iterator, callback)
  245 +
  246 +__alias:__ selectSeries
  247 +
  248 +The same as filter only the iterator is applied to each item in the array in
  249 +series. The next iterator is only called once the current one has completed
  250 +processing. The results array will be in the same order as the original.
  251 +
  252 +---------------------------------------
  253 +
  254 +<a name="reject" />
  255 +### reject(arr, iterator, callback)
  256 +
  257 +The opposite of filter. Removes values that pass an async truth test.
  258 +
  259 +---------------------------------------
  260 +
  261 +<a name="rejectSeries" />
  262 +### rejectSeries(arr, iterator, callback)
  263 +
  264 +The same as filter, only the iterator is applied to each item in the array
  265 +in series.
  266 +
  267 +
  268 +---------------------------------------
  269 +
  270 +<a name="reduce" />
  271 +### reduce(arr, memo, iterator, callback)
  272 +
  273 +__aliases:__ inject, foldl
  274 +
  275 +Reduces a list of values into a single value using an async iterator to return
  276 +each successive step. Memo is the initial state of the reduction. This
  277 +function only operates in series. For performance reasons, it may make sense to
  278 +split a call to this function into a parallel map, then use the normal
  279 +Array.prototype.reduce on the results. This function is for situations where
  280 +each step in the reduction needs to be async, if you can get the data before
  281 +reducing it then its probably a good idea to do so.
  282 +
  283 +__Arguments__
  284 +
  285 +* arr - An array to iterate over.
  286 +* memo - The initial state of the reduction.
  287 +* iterator(memo, item, callback) - A function applied to each item in the
  288 + array to produce the next step in the reduction. The iterator is passed a
  289 + callback which accepts an optional error as its first argument, and the state
  290 + of the reduction as the second. If an error is passed to the callback, the
  291 + reduction is stopped and the main callback is immediately called with the
  292 + error.
  293 +* callback(err, result) - A callback which is called after all the iterator
  294 + functions have finished. Result is the reduced value.
  295 +
  296 +__Example__
  297 +
  298 + async.reduce([1,2,3], 0, function(memo, item, callback){
  299 + // pointless async:
  300 + process.nextTick(function(){
  301 + callback(null, memo + item)
  302 + });
  303 + }, function(err, result){
  304 + // result is now equal to the last value of memo, which is 6
  305 + });
  306 +
  307 +---------------------------------------
  308 +
  309 +<a name="reduceRight" />
  310 +### reduceRight(arr, memo, iterator, callback)
  311 +
  312 +__Alias:__ foldr
  313 +
  314 +Same as reduce, only operates on the items in the array in reverse order.
  315 +
  316 +
  317 +---------------------------------------
  318 +
  319 +<a name="detect" />
  320 +### detect(arr, iterator, callback)
  321 +
  322 +Returns the first value in a list that passes an async truth test. The
  323 +iterator is applied in parallel, meaning the first iterator to return true will
  324 +fire the detect callback with that result. That means the result might not be
  325 +the first item in the original array (in terms of order) that passes the test.
  326 +
  327 +If order within the original array is important then look at detectSeries.
  328 +
  329 +__Arguments__
  330 +
  331 +* arr - An array to iterate over.
  332 +* iterator(item, callback) - A truth test to apply to each item in the array.
  333 + The iterator is passed a callback which must be called once it has completed.
  334 +* callback(result) - A callback which is called as soon as any iterator returns
  335 + true, or after all the iterator functions have finished. Result will be
  336 + the first item in the array that passes the truth test (iterator) or the
  337 + value undefined if none passed.
  338 +
  339 +__Example__
  340 +
  341 + async.detect(['file1','file2','file3'], path.exists, function(result){
  342 + // result now equals the first file in the list that exists
  343 + });
  344 +
  345 +---------------------------------------
  346 +
  347 +<a name="detectSeries" />
  348 +### detectSeries(arr, iterator, callback)
  349 +
  350 +The same as detect, only the iterator is applied to each item in the array
  351 +in series. This means the result is always the first in the original array (in
  352 +terms of array order) that passes the truth test.
  353 +
  354 +
  355 +---------------------------------------
  356 +
  357 +<a name="sortBy" />
  358 +### sortBy(arr, iterator, callback)
  359 +
  360 +Sorts a list by the results of running each value through an async iterator.
  361 +
  362 +__Arguments__
  363 +
  364 +* arr - An array to iterate over.
  365 +* iterator(item, callback) - A function to apply to each item in the array.
  366 + The iterator is passed a callback which must be called once it has completed
  367 + with an error (which can be null) and a value to use as the sort criteria.
  368 +* callback(err, results) - A callback which is called after all the iterator
  369 + functions have finished, or an error has occurred. Results is the items from
  370 + the original array sorted by the values returned by the iterator calls.
  371 +
  372 +__Example__
  373 +
  374 + async.sortBy(['file1','file2','file3'], function(file, callback){
  375 + fs.stat(file, function(err, stats){
  376 + callback(err, stats.mtime);
  377 + });
  378 + }, function(err, results){
  379 + // results is now the original array of files sorted by
  380 + // modified date
  381 + });
  382 +
  383 +
  384 +---------------------------------------
  385 +
  386 +<a name="some" />
  387 +### some(arr, iterator, callback)
  388 +
  389 +__Alias:__ any
  390 +
  391 +Returns true if at least one element in the array satisfies an async test.
  392 +_The callback for each iterator call only accepts a single argument of true or
  393 +false, it does not accept an error argument first!_ This is in-line with the
  394 +way node libraries work with truth tests like path.exists. Once any iterator
  395 +call returns true, the main callback is immediately called.
  396 +
  397 +__Arguments__
  398 +
  399 +* arr - An array to iterate over.
  400 +* iterator(item, callback) - A truth test to apply to each item in the array.
  401 + The iterator is passed a callback which must be called once it has completed.
  402 +* callback(result) - A callback which is called as soon as any iterator returns
  403 + true, or after all the iterator functions have finished. Result will be
  404 + either true or false depending on the values of the async tests.
  405 +
  406 +__Example__
  407 +
  408 + async.some(['file1','file2','file3'], path.exists, function(result){
  409 + // if result is true then at least one of the files exists
  410 + });
  411 +
  412 +---------------------------------------
  413 +
  414 +<a name="every" />
  415 +### every(arr, iterator, callback)
  416 +
  417 +__Alias:__ all
  418 +
  419 +Returns true if every element in the array satisfies an async test.
  420 +_The callback for each iterator call only accepts a single argument of true or
  421 +false, it does not accept an error argument first!_ This is in-line with the
  422 +way node libraries work with truth tests like path.exists.
  423 +
  424 +__Arguments__
  425 +
  426 +* arr - An array to iterate over.
  427 +* iterator(item, callback) - A truth test to apply to each item in the array.
  428 + The iterator is passed a callback which must be called once it has completed.
  429 +* callback(result) - A callback which is called after all the iterator
  430 + functions have finished. Result will be either true or false depending on
  431 + the values of the async tests.
  432 +
  433 +__Example__
  434 +
  435 + async.every(['file1','file2','file3'], path.exists, function(result){
  436 + // if result is true then every file exists
  437 + });
  438 +
  439 +---------------------------------------
  440 +
  441 +<a name="concat" />
  442 +### concat(arr, iterator, callback)
  443 +
  444 +Applies an iterator to each item in a list, concatenating the results. Returns the
  445 +concatenated list. The iterators are called in parallel, and the results are
  446 +concatenated as they return. There is no guarantee that the results array will
  447 +be returned in the original order of the arguments passed to the iterator function.
  448 +
  449 +__Arguments__
  450 +
  451 +* arr - An array to iterate over
  452 +* iterator(item, callback) - A function to apply to each item in the array.
  453 + The iterator is passed a callback which must be called once it has completed
  454 + with an error (which can be null) and an array of results.
  455 +* callback(err, results) - A callback which is called after all the iterator
  456 + functions have finished, or an error has occurred. Results is an array containing
  457 + the concatenated results of the iterator function.
  458 +
  459 +__Example__
  460 +
  461 + async.concat(['dir1','dir2','dir3'], fs.readdir, function(err, files){
  462 + // files is now a list of filenames that exist in the 3 directories
  463 + });
  464 +
  465 +---------------------------------------
  466 +
  467 +<a name="concatSeries" />
  468 +### concatSeries(arr, iterator, callback)
  469 +
  470 +Same as async.concat, but executes in series instead of parallel.
  471 +
  472 +
  473 +## Control Flow
  474 +
  475 +<a name="series" />
  476 +### series(tasks, [callback])
  477 +
  478 +Run an array of functions in series, each one running once the previous
  479 +function has completed. If any functions in the series pass an error to its
  480 +callback, no more functions are run and the callback for the series is
  481 +immediately called with the value of the error. Once the tasks have completed,
  482 +the results are passed to the final callback as an array.
  483 +
  484 +It is also possible to use an object instead of an array. Each property will be
  485 +run as a function and the results will be passed to the final callback as an object
  486 +instead of an array. This can be a more readable way of handling results from
  487 +async.series.
  488 +
  489 +
  490 +__Arguments__
  491 +
  492 +* tasks - An array or object containing functions to run, each function is passed
  493 + a callback it must call on completion.
  494 +* callback(err, results) - An optional callback to run once all the functions
  495 + have completed. This function gets an array of all the arguments passed to
  496 + the callbacks used in the array.
  497 +
  498 +__Example__
  499 +
  500 + async.series([
  501 + function(callback){
  502 + // do some stuff ...
  503 + callback(null, 'one');
  504 + },
  505 + function(callback){
  506 + // do some more stuff ...
  507 + callback(null, 'two');
  508 + },
  509 + ],
  510 + // optional callback
  511 + function(err, results){
  512 + // results is now equal to ['one', 'two']
  513 + });
  514 +
  515 +
  516 + // an example using an object instead of an array
  517 + async.series({
  518 + one: function(callback){
  519 + setTimeout(function(){
  520 + callback(null, 1);
  521 + }, 200);
  522 + },
  523 + two: function(callback){
  524 + setTimeout(function(){
  525 + callback(null, 2);
  526 + }, 100);
  527 + },
  528 + },
  529 + function(err, results) {
  530 + // results is now equal to: {one: 1, two: 2}
  531 + });
  532 +
  533 +
  534 +---------------------------------------
  535 +
  536 +<a name="parallel" />
  537 +### parallel(tasks, [callback])
  538 +
  539 +Run an array of functions in parallel, without waiting until the previous
  540 +function has completed. If any of the functions pass an error to its
  541 +callback, the main callback is immediately called with the value of the error.
  542 +Once the tasks have completed, the results are passed to the final callback as an
  543 +array.
  544 +
  545 +It is also possible to use an object instead of an array. Each property will be
  546 +run as a function and the results will be passed to the final callback as an object
  547 +instead of an array. This can be a more readable way of handling results from
  548 +async.parallel.
  549 +
  550 +
  551 +__Arguments__
  552 +
  553 +* tasks - An array or object containing functions to run, each function is passed a
  554 + callback it must call on completion.
  555 +* callback(err, results) - An optional callback to run once all the functions
  556 + have completed. This function gets an array of all the arguments passed to
  557 + the callbacks used in the array.
  558 +
  559 +__Example__
  560 +
  561 + async.parallel([
  562 + function(callback){
  563 + setTimeout(function(){
  564 + callback(null, 'one');
  565 + }, 200);
  566 + },
  567 + function(callback){
  568 + setTimeout(function(){
  569 + callback(null, 'two');
  570 + }, 100);
  571 + },
  572 + ],
  573 + // optional callback
  574 + function(err, results){
  575 + // in this case, the results array will equal ['two','one']
  576 + // because the functions were run in parallel and the second
  577 + // function had a shorter timeout before calling the callback.
  578 + });
  579 +
  580 +
  581 + // an example using an object instead of an array
  582 + async.parallel({
  583 + one: function(callback){
  584 + setTimeout(function(){
  585 + callback(null, 1);
  586 + }, 200);
  587 + },
  588 + two: function(callback){
  589 + setTimeout(function(){
  590 + callback(null, 2);
  591 + }, 100);
  592 + },
  593 + },
  594 + function(err, results) {
  595 + // results is now equals to: {one: 1, two: 2}
  596 + });
  597 +
  598 +
  599 +---------------------------------------
  600 +
  601 +<a name="whilst" />
  602 +### whilst(test, fn, callback)
  603 +
  604 +Repeatedly call fn, while test returns true. Calls the callback when stopped,
  605 +or an error occurs.
  606 +
  607 +__Arguments__
  608 +
  609 +* test() - synchronous truth test to perform before each execution of fn.
  610 +* fn(callback) - A function to call each time the test passes. The function is
  611 + passed a callback which must be called once it has completed with an optional
  612 + error as the first argument.
  613 +* callback(err) - A callback which is called after the test fails and repeated
  614 + execution of fn has stopped.
  615 +
  616 +__Example__
  617 +
  618 + var count = 0;
  619 +
  620 + async.whilst(
  621 + function () { return count < 5; },
  622 + function (callback) {
  623 + count++;
  624 + setTimeout(callback, 1000);
  625 + },
  626 + function (err) {
  627 + // 5 seconds have passed
  628 + }
  629 + );
  630 +
  631 +
  632 +---------------------------------------
  633 +
  634 +<a name="until" />
  635 +### until(test, fn, callback)
  636 +
  637 +Repeatedly call fn, until test returns true. Calls the callback when stopped,
  638 +or an error occurs.
  639 +
  640 +The inverse of async.whilst.
  641 +
  642 +
  643 +---------------------------------------
  644 +
  645 +<a name="waterfall" />
  646 +### waterfall(tasks, [callback])
  647 +
  648 +Runs an array of functions in series, each passing their results to the next in
  649 +the array. However, if any of the functions pass an error to the callback, the
  650 +next function is not executed and the main callback is immediately called with
  651 +the error.
  652 +
  653 +__Arguments__
  654 +
  655 +* tasks - An array of functions to run, each function is passed a callback it
  656 + must call on completion.
  657 +* callback(err, [results]) - An optional callback to run once all the functions
  658 + have completed. This will be passed the results of the last task's callback.
  659 +
  660 +
  661 +
  662 +__Example__
  663 +
  664 + async.waterfall([
  665 + function(callback){
  666 + callback(null, 'one', 'two');
  667 + },
  668 + function(arg1, arg2, callback){
  669 + callback(null, 'three');
  670 + },
  671 + function(arg1, callback){
  672 + // arg1 now equals 'three'
  673 + callback(null, 'done');
  674 + }
  675 + ], function (err, result) {
  676 + // result now equals 'done'
  677 + });
  678 +
  679 +
  680 +---------------------------------------
  681 +
  682 +<a name="queue" />
  683 +### queue(worker, concurrency)
  684 +
  685 +Creates a queue object with the specified concurrency. Tasks added to the
  686 +queue will be processed in parallel (up to the concurrency limit). If all
  687 +workers are in progress, the task is queued until one is available. Once
  688 +a worker has completed a task, the task's callback is called.
  689 +
  690 +__Arguments__
  691 +
  692 +* worker(task, callback) - An asynchronous function for processing a queued
  693 + task.
  694 +* concurrency - An integer for determining how many worker functions should be
  695 + run in parallel.
  696 +
  697 +__Queue objects__
  698 +
  699 +The queue object returned by this function has the following properties and
  700 +methods:
  701 +
  702 +* length() - a function returning the number of items waiting to be processed.
  703 +* concurrency - an integer for determining how many worker functions should be
  704 + run in parallel. This property can be changed after a queue is created to
  705 + alter the concurrency on-the-fly.
  706 +* push(task, [callback]) - add a new task to the queue, the callback is called
  707 + once the worker has finished processing the task.
  708 + instead of a single task, an array of tasks can be submitted. the respective callback is used for every task in the list.
  709 +* saturated - a callback that is called when the queue length hits the concurrency and further tasks will be queued
  710 +* empty - a callback that is called when the last item from the queue is given to a worker
  711 +* drain - a callback that is called when the last item from the queue has returned from the worker
  712 +
  713 +__Example__
  714 +
  715 + // create a queue object with concurrency 2
  716 +
  717 + var q = async.queue(function (task, callback) {
  718 + console.log('hello ' + task.name);
  719 + callback();
  720 + }, 2);
  721 +
  722 +
  723 + // assign a callback
  724 + q.drain = function() {
  725 + console.log('all items have been processed');
  726 + }
  727 +
  728 + // add some items to the queue
  729 +
  730 + q.push({name: 'foo'}, function (err) {
  731 + console.log('finished processing foo');
  732 + });
  733 + q.push({name: 'bar'}, function (err) {
  734 + console.log('finished processing bar');
  735 + });
  736 +
  737 + // add some items to the queue (batch-wise)
  738 +
  739 + q.push([{name: 'baz'},{name: 'bay'},{name: 'bax'}], function (err) {
  740 + console.log('finished processing bar');
  741 + });
  742 +
  743 +
  744 +---------------------------------------
  745 +
  746 +<a name="auto" />
  747 +### auto(tasks, [callback])
  748 +
  749 +Determines the best order for running functions based on their requirements.
  750 +Each function can optionally depend on other functions being completed first,
  751 +and each function is run as soon as its requirements are satisfied. If any of
  752 +the functions pass an error to their callback, that function will not complete
  753 +(so any other functions depending on it will not run) and the main callback
  754 +will be called immediately with the error. Functions also receive an object
  755 +containing the results of functions which have completed so far.
  756 +
  757 +__Arguments__
  758 +
  759 +* tasks - An object literal containing named functions or an array of
  760 + requirements, with the function itself the last item in the array. The key
  761 + used for each function or array is used when specifying requirements. The
  762 + syntax is easier to understand by looking at the example.
  763 +* callback(err, results) - An optional callback which is called when all the
  764 + tasks have been completed. The callback will receive an error as an argument
  765 + if any tasks pass an error to their callback. If all tasks complete
  766 + successfully, it will receive an object containing their results.
  767 +
  768 +__Example__
  769 +
  770 + async.auto({
  771 + get_data: function(callback){
  772 + // async code to get some data
  773 + },
  774 + make_folder: function(callback){
  775 + // async code to create a directory to store a file in
  776 + // this is run at the same time as getting the data
  777 + },
  778 + write_file: ['get_data', 'make_folder', function(callback){
  779 + // once there is some data and the directory exists,
  780 + // write the data to a file in the directory
  781 + callback(null, filename);
  782 + }],
  783 + email_link: ['write_file', function(callback, results){
  784 + // once the file is written let's email a link to it...
  785 + // results.write_file contains the filename returned by write_file.
  786 + }]
  787 + });
  788 +
  789 +This is a fairly trivial example, but to do this using the basic parallel and
  790 +series functions would look like this:
  791 +
  792 + async.parallel([
  793 + function(callback){
  794 + // async code to get some data
  795 + },
  796 + function(callback){
  797 + // async code to create a directory to store a file in
  798 + // this is run at the same time as getting the data
  799 + }
  800 + ],
  801 + function(results){
  802 + async.series([
  803 + function(callback){
  804 + // once there is some data and the directory exists,
  805 + // write the data to a file in the directory
  806 + },
  807 + email_link: function(callback){
  808 + // once the file is written let's email a link to it...
  809 + }
  810 + ]);
  811 + });
  812 +
  813 +For a complicated series of async tasks using the auto function makes adding
  814 +new tasks much easier and makes the code more readable.
  815 +
  816 +
  817 +---------------------------------------
  818 +
  819 +<a name="iterator" />
  820 +### iterator(tasks)
  821 +
  822 +Creates an iterator function which calls the next function in the array,
  823 +returning a continuation to call the next one after that. Its also possible to
  824 +'peek' the next iterator by doing iterator.next().
  825 +
  826 +This function is used internally by the async module but can be useful when
  827 +you want to manually control the flow of functions in series.
  828 +
  829 +__Arguments__
  830 +
  831 +* tasks - An array of functions to run, each function is passed a callback it
  832 + must call on completion.
  833 +
  834 +__Example__
  835 +
  836 + var iterator = async.iterator([
  837 + function(){ sys.p('one'); },
  838 + function(){ sys.p('two'); },
  839 + function(){ sys.p('three'); }
  840 + ]);
  841 +
  842 + node> var iterator2 = iterator();
  843 + 'one'
  844 + node> var iterator3 = iterator2();
  845 + 'two'
  846 + node> iterator3();
  847 + 'three'
  848 + node> var nextfn = iterator2.next();
  849 + node> nextfn();
  850 + 'three'
  851 +
  852 +
  853 +---------------------------------------
  854 +
  855 +<a name="apply" />
  856 +### apply(function, arguments..)
  857 +
  858 +Creates a continuation function with some arguments already applied, a useful
  859 +shorthand when combined with other control flow functions. Any arguments
  860 +passed to the returned function are added to the arguments originally passed
  861 +to apply.
  862 +
  863 +__Arguments__
  864 +
  865 +* function - The function you want to eventually apply all arguments to.
  866 +* arguments... - Any number of arguments to automatically apply when the
  867 + continuation is called.
  868 +
  869 +__Example__
  870 +
  871 + // using apply
  872 +
  873 + async.parallel([
  874 + async.apply(fs.writeFile, 'testfile1', 'test1'),
  875 + async.apply(fs.writeFile, 'testfile2', 'test2'),
  876 + ]);
  877 +
  878 +
  879 + // the same process without using apply
  880 +
  881 + async.parallel([
  882 + function(callback){
  883 + fs.writeFile('testfile1', 'test1', callback);
  884 + },
  885 + function(callback){
  886 + fs.writeFile('testfile2', 'test2', callback);
  887 + },
  888 + ]);
  889 +
  890 +It's possible to pass any number of additional arguments when calling the
  891 +continuation:
  892 +
  893 + node> var fn = async.apply(sys.puts, 'one');
  894 + node> fn('two', 'three');
  895 + one
  896 + two
  897 + three
  898 +
  899 +---------------------------------------
  900 +
  901 +<a name="nextTick" />
  902 +### nextTick(callback)
  903 +
  904 +Calls the callback on a later loop around the event loop. In node.js this just
  905 +calls process.nextTick, in the browser it falls back to setTimeout(callback, 0),
  906 +which means other higher priority events may precede the execution of the callback.
  907 +
  908 +This is used internally for browser-compatibility purposes.
  909 +
  910 +__Arguments__
  911 +
  912 +* callback - The function to call on a later loop around the event loop.
  913 +
  914 +__Example__
  915 +
  916 + var call_order = [];