├── .gitignore ├── README.md ├── apply.js ├── applyEach.js ├── auto.js ├── cargo.js ├── compose.js ├── concat.js ├── detect.js ├── each.js ├── every.js ├── filter_reject.js ├── iterator.js ├── map.js ├── nextTick.js ├── package.json ├── parallel.js ├── queue.js ├── reduce.js ├── series.js ├── some.js ├── sortBy.js ├── t.js ├── times.js ├── utils.js ├── waterfall.js └── whilst_until.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .idea -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | async_demo 2 | ========== 3 | 4 | A demo for async. 5 | 6 | + http://blog.fens.me/nodejs-async/ 7 | + http://blog.fens.me/nodejs-async-timer/ 8 | 9 | INSTALL 10 | =========================== 11 | 12 | ```{bash} 13 | git clone https://github.com/bsspirit/async_demo.git 14 | cd async_demo 15 | ``` 16 | 17 | Change Log 18 | =================================== 19 | 20 | 参考async@0.2.9版本的规范 21 | 22 | https://github.com/caolan/async 23 | 24 | 1. forEach.js改名为each.js 25 | 2. each.js文件中的async.forEach,改为async.each 26 | 3. map.js增加mapLimit函数 27 | 4. filter_reject.js对注释补充 28 | 5. filter_reject.js增加rejectSeries函数 29 | 6. reduce.js增加注释 30 | 7. detect.js增加注释 31 | 8. sortBy.js增加注释 32 | 9. some.js对注释补充 33 | 10. every.js对注释补充和修改 34 | 11. series.js调整注释格式 35 | 12. parallel.js调整注释格式 36 | 13. parallel.js增加parallelLimit函数 37 | 14. whilist_until.js调整注释格式 38 | 15. whilist_until.js增加doWhilst函数 39 | 16. whilist_until.js增加doUntil函数 40 | 17. whilist_until.js增加forever函数 41 | 18. waterfall.js调整注释格式 42 | 19. 增加compose.js文件 43 | 20. apply.js补充注释并增加一个实例 44 | 21. 修改nextTick.js实例 45 | 22. 增加times.js文件,包括times和timesSeries函数 46 | 23. 修改iterator.js实例 47 | 24. 修正auto.js关于第二个实例的错误解释 48 | 25. 修改queue.js实例和注释 49 | 26. 修改cargo.js文件 50 | 27. 增加applyEach.js文件 51 | 28. 修改utils.js实例和注释 52 | 53 | 54 | -------------------------------------------------------------------------------- /apply.js: -------------------------------------------------------------------------------- 1 | var async = require('async'); 2 | 3 | var t = require('./t'); 4 | var log = t.log; 5 | 6 | /** 7 | * apply是一个非常好用的函数,可以让我们给一个函数预绑定多个参数并生成一个可直接调用的新函数,简化代码。 8 | * 9 | * function(callback) { t.inc(3, callback); } 10 | * 等价于: 11 | * async.apply(t.inc, 3); 12 | */ 13 | // apply(function, arguments..) 14 | 15 | /** 16 | * 通过名字绑定函数t.inc, t.fire,作为新函数给parallel调用 17 | */ 18 | //1.1 19 | async.parallel([ 20 | async.apply(t.inc, 3), 21 | async.apply(t.fire, 100) 22 | ], function (err, results) { 23 | log('1.1 err: ', err); 24 | log('1.1 results: ', results); 25 | }); 26 | //58.605> 1.1 err: null 27 | //58.613> 1.1 results: [ 4, 100 ] 28 | 29 | /** 30 | * 构造一个加法函数,通过apply简化代码 31 | */ 32 | //1.2 33 | function inc(a,b,callback,timeout){ 34 | var timeout = timeout || 200; 35 | t.wait(200); 36 | setTimeout(function() { 37 | callback(null, a+b); 38 | }, timeout); 39 | } 40 | var fn = async.apply(inc, 1, 2); 41 | fn(function(err, n){ 42 | log('1.2 inc: ' + n); 43 | }); 44 | //58.616> 1.2 inc: 3 -------------------------------------------------------------------------------- /applyEach.js: -------------------------------------------------------------------------------- 1 | var async = require('async'); 2 | var t = require('./t'); 3 | var log = t.log; 4 | 5 | /** 6 | * applyEach,可以实现给一数组中每个函数传相同参数,通过callback返回。 7 | * 如果只传第一个参数,将返回一个函数对象,我可以传参调用。 8 | */ 9 | // applyEach(fns, args..., callback) 10 | 11 | /** 12 | * 异步执行,给数组中的函数,他们有相同的参数。 13 | */ 14 | //1.1 15 | async.applyEach([ 16 | function (name,cb) { 17 | setTimeout(function () { 18 | log("1.1 handler: " + name + " A"); 19 | cb(null, name); 20 | }, 500); 21 | }, function (name,cb) { 22 | setTimeout(function () { 23 | log("1.1 handler: " + name + " B"); 24 | cb(null, name); 25 | }, 150); 26 | } 27 | ], 'Hello', function (err) { 28 | log('1.1 err: ', err); 29 | }); 30 | //06.739> 1.1 handler: Hello B 31 | //07.079> 1.1 handler: Hello A 32 | //07.080> 1.1 err: null 33 | 34 | /** 35 | * 异步执行,当只设置第一参数后,得到函数对象,再传参调用这个函数。 36 | */ 37 | //1.2 38 | var fn = async.applyEach([ 39 | function (name,cb) { 40 | setTimeout(function () { 41 | log("1.2 handler: " + name + " A"); 42 | }, 500); 43 | }, function (name,cb) { 44 | setTimeout(function () { 45 | log("1.2 handler: " + name + " B"); 46 | }, 150); 47 | } 48 | ]); 49 | fn("simgle",function(err){ 50 | log('err: ',err); 51 | }); 52 | //29.351> 1.2 handler: simgle B 53 | //29.688> 1.2 handler: simgle A 54 | 55 | /** 56 | * applyEachSeries与applyEach唯一不同的是,数组的函数同步执行。 57 | */ 58 | //applyEachSeries(arr, args..., callback) 59 | //1.3 60 | async.applyEachSeries([ 61 | function (name,cb) { 62 | setTimeout(function () { 63 | log("1.3 handler: " + name + " A"); 64 | cb(null, name); 65 | }, 500); 66 | }, function (name,cb) { 67 | setTimeout(function () { 68 | log("1.3 handler: " + name + " B"); 69 | cb(null, name); 70 | }, 150); 71 | } 72 | ], "aaa", function (err) { 73 | log('1.3 err: ', err); 74 | }); 75 | //10.669> 1.3 handler: aaa A 76 | //10.831> 1.3 handler: aaa B 77 | //10.834> 1.3 err: null 78 | 79 | 80 | -------------------------------------------------------------------------------- /auto.js: -------------------------------------------------------------------------------- 1 | var async = require('async'); 2 | var t = require('./t'); 3 | var log = t.log; 4 | 5 | /** 6 | * auto用来处理有依赖关系的多个任务的执行。 7 | * 8 | * 比如某些任务之间彼此独立,可以并行执行;但某些任务依赖于其它某些任务,只能等那些任务完成后才能执行。 9 | * 虽然我们可以使用parallel和series结合起来实现该功能,但如果任务之间关系复杂,则代码会相当复杂,以后如果想添加一个新任务,也会很麻烦。 10 | * 这时使用auto,则会事半功倍。 11 | * 12 | * 如果有任务中途出错,则会把该错误传给最终callback,所有任务(包括已经执行完的)产生的数据将被忽略。 13 | * 如果不关心错误和最终数据,可以不用写最后那个callback。 14 | */ 15 | // async.auto(tasks, [callback]) 16 | 17 | /** 18 | * 我要写一个程序,它要完成以下几件事: 19 | * 1. 从某处取得数据 20 | * 2. 在硬盘上建立一个新的目录 21 | * 3. 将数据写入到目录下某文件 22 | * 4. 发送邮件,将文件以附件形式发送给其它人。 23 | * 24 | * 分析该任务,可以知道1与2可以并行执行,3需要等1和2完成,4要等3完成。 25 | * 可以按以下方式来使用auto函数。 26 | */ 27 | // 1.1 28 | async.auto({ 29 | getData: function (callback) { 30 | setTimeout(function(){ 31 | console.log('1.1: got data'); 32 | callback(null, 'mydata'); 33 | }, 300); 34 | }, 35 | makeFolder: function (callback) { 36 | setTimeout(function(){ 37 | console.log('1.1: made folder'); 38 | callback(null, 'myfolder'); 39 | }, 200); 40 | }, 41 | writeFile: ['getData', 'makeFolder', function(callback) { 42 | setTimeout(function(){ 43 | console.log('1.1: wrote file'); 44 | callback(null, 'myfile'); 45 | }, 300); 46 | }], 47 | emailFiles: ['writeFile', function(callback, results) { 48 | log('1.1: emailed file: ', results.writeFile); 49 | callback(null, results.writeFile); 50 | }] 51 | }, function(err, results) { 52 | log('1.1: err: ', err); 53 | log('1.1: results: ', results); 54 | }); 55 | //1.1: made folder 56 | //1.1: got data 57 | //1.1: wrote file 58 | //20.120> 1.1: emailed file: myfile 59 | //20.125> 1.1: err: null 60 | //20.127> 1.1: results: { makeFolder: 'myfolder', 61 | // getData: 'mydata', 62 | // writeFile: 'myfile', 63 | // emailFiles: 'myfile' } 64 | 65 | 66 | 67 | /** 68 | * 如果中途出错,则会把错误交给最终callback,执行完任务的传给最终callback。未执行完成的函数值被忽略 69 | */ 70 | // 1.2 71 | async.auto({ 72 | getData: function (callback) { 73 | setTimeout(function(){ 74 | console.log('1.2: got data'); 75 | callback(null, 'mydata'); 76 | }, 300); 77 | }, 78 | makeFolder: function (callback) { 79 | setTimeout(function(){ 80 | console.log('1.2: made folder'); 81 | callback(null, 'myfolder'); 82 | }, 200); 83 | }, 84 | writeFile: ['getData', 'makeFolder', function(callback, results) { 85 | setTimeout(function(){ 86 | console.log('1.2: wrote file'); 87 | callback('myerr'); 88 | }, 300); 89 | }], 90 | emailFiles: ['writeFile', function(callback, results) { 91 | console.log('1.2: emailed file: ' + results.writeFile); 92 | callback('err sending email', results.writeFile); 93 | }] 94 | }, function(err, results) { 95 | log('1.2 err: ', err); 96 | log('1.2 results: ', results); 97 | }); 98 | //1.2: made folder 99 | //1.2: got data 100 | //1.2: wrote file 101 | //51.399> 1.2 err: myerr 102 | //51.401> 1.2 results: { makeFolder: 'myfolder', 103 | // getData: 'mydata', 104 | // writeFile: undefined } 105 | -------------------------------------------------------------------------------- /cargo.js: -------------------------------------------------------------------------------- 1 | var async = require('async'); 2 | var t = require('./t'); 3 | var log = t.log; 4 | 5 | /** 6 | * cargo也是一个串行的消息队列,类似于queue,通过限制了worker数量,不再一次性全部执行。 7 | * 当worker数量不够用时,新加入的任务将会排队等候,直到有新的worker可用。 8 | * 9 | * cargo的不同之处在于,cargo每次会加载满额的任务做为任务单元,只有任务单元中全部执行完成后,才会加载新的任务单元。 10 | */ 11 | // cargo(worker, [payload]) 12 | 13 | /** 14 | * 创建cargo实例 15 | */ 16 | var cargo = async.cargo(function (tasks, callback) { 17 | for(var i=0; i all workers to be used 69 | //40.020> no more tasks wating 70 | //40.020> start A 71 | //40.020> start B 72 | //40.322> finished processing A 73 | //40.923> finished processing B 74 | //40.923> no more tasks wating 75 | //40.924> start C 76 | //40.924> start D 77 | //41.425> finished processing C 78 | //41.526> finished processing D 79 | //41.526> no more tasks wating 80 | //41.527> start E 81 | //41.728> finished processing E 82 | //41.728> all tasks have been processed 83 | //41.729> all tasks have been processed 84 | //41.729> all tasks have been processed 85 | //41.729> all tasks have been processed 86 | //41.730> all tasks have been processed -------------------------------------------------------------------------------- /compose.js: -------------------------------------------------------------------------------- 1 | var async = require('async'); 2 | var t = require('./t'); 3 | var log = t.log; 4 | 5 | /** 6 | * 创建一个包括一组异步函数的函数集合,每个函数会消费上一次函数的返回值。 7 | * 把f(),g(),h()异步函数,组合成f(g(h()))的形式,通过callback得到返回值。 8 | */ 9 | // compose(fn1, fn2...) 10 | 11 | /** 12 | * 通过compose组合,f(g(h()))的形式,从内层到外层的执行的顺序。 13 | */ 14 | //1.1 15 | function f(n,callback){ 16 | log('1.1.f enter: ',n); 17 | setTimeout(function () { 18 | callback(null, n + 1); 19 | }, 10); 20 | } 21 | function g(n, callback) { 22 | log('1.1.g enter: ',n); 23 | setTimeout(function () { 24 | callback(null, n * 2); 25 | }, 10); 26 | } 27 | function h(n, callback) { 28 | log('1.1.h enter: ',n); 29 | setTimeout(function () { 30 | callback(null, n - 10); 31 | }, 10); 32 | } 33 | var fgh = async.compose(f,g,h); 34 | fgh(4,function(err,result){ 35 | log('1.1 err: ', err); 36 | log('1.1 result: ', result); 37 | }); 38 | //05.307> 1.1.h enter: 4 39 | //05.329> 1.1.g enter: -6 40 | //05.341> 1.1.f enter: -12 41 | //05.361> 1.1 err: null 42 | //05.362> 1.1 result: -11 -------------------------------------------------------------------------------- /concat.js: -------------------------------------------------------------------------------- 1 | var async = require('async'); 2 | 3 | var t = require('./t'); 4 | var log = t.log; 5 | 6 | /** 7 | * 将多个异步操作的结果合并为一个数组。 8 | */ 9 | // concat(arr, iterator(item,callback(err,result)), callback(err,result)) 10 | 11 | var data = { 12 | aaa: [11,22,33], 13 | bbb: [44,55], 14 | ccc: 66 15 | }; 16 | 17 | var keys = [ 18 | {name: 'aaa', delay: 300}, 19 | {name: 'bbb', delay: 100}, 20 | {name: 'ccc', delay: 200} 21 | ]; 22 | 23 | /** 24 | * 以并行方式对集合中各元素进行异步操作,然后把得到的结果合并为一个数组,传给最后的callback。 25 | */ 26 | // 1.1 27 | async.concat(keys, function(key,callback) { 28 | setTimeout(function() { 29 | callback(null, data[key.name]); 30 | }, key.delay); 31 | }, function(err, values) { 32 | log('1.1 err: ', err); 33 | log('1.1 values: ', values); 34 | }); 35 | // 13.539> 1.1 err: 36 | // 13.539> 1.1 values: [ 44, 55, 66, 11, 22, 33 ] 37 | 38 | /** 39 | * 如果中途出错,则把错误以及已经完成的操作的结果交给最后callback。未执行完的则忽略。 40 | */ 41 | // 1.2 42 | async.concat(keys, function(key,callback) { 43 | setTimeout(function() { 44 | if(key.name==='ccc') callback('myerr'); 45 | else callback(null, data[key.name]); 46 | }, key.delay); 47 | }, function(err, values) { 48 | log('1.2 err: ', err); 49 | log('1.2 values: ', values); 50 | }); 51 | // 13.439> 1.2 err: myerr 52 | // 13.439> 1.2 values: [ 44, 55 ] 53 | 54 | /** 55 | * 按数组中的元素顺序来执行异步操作,一个完成后才对下一个进行操作。所有结果会汇集成一个数组交给最后的callback。 56 | */ 57 | // concatSeries(arr, iterator, callback) 58 | 59 | // 1.3 60 | async.concatSeries(keys, function(key,callback) { 61 | setTimeout(function() { 62 | callback(null, data[key.name]); 63 | }, key.delay); 64 | }, function(err, values) { 65 | log('1.3 err: ', err); 66 | log('1.3 values: ', values); 67 | }); 68 | // 13.859> 1.3 err: 69 | // 13.859> 1.3 values: [ 11, 22, 33, 44, 55, 66 ] -------------------------------------------------------------------------------- /detect.js: -------------------------------------------------------------------------------- 1 | var async = require('async'); 2 | 3 | var t = require('./t'); 4 | var log = t.log; 5 | 6 | /** 7 | * 用于取得集合中满足条件的第一个元素。 8 | * 它分为并行与顺序执行两种方式,分别对应函数detect和detectSeries。 9 | */ 10 | // detect(array, iterator(item,callback(test)), callback(result) 11 | 12 | var arr = [ 13 | {value:1,delay:500}, 14 | {value:2,delay:200}, 15 | {value:3,delay:300} 16 | ]; 17 | 18 | /** 19 | * 并行执行,通过t.inc做一个累加器,得到第一个满足条件的结果对象 20 | */ 21 | async.detect(arr, function(item,callback){ 22 | log('1.1 enter: ', item.value); 23 | t.inc(item.value, function(err,n) { 24 | log('1.1 handle: ', item.value); 25 | callback(n%2===0); 26 | }, item.delay); 27 | }, function(result) { 28 | log('1.1 result: ', result); 29 | }); 30 | // 09.928> 1.1 enter: 1 31 | // 09.928> 1.1 enter: 2 32 | // 09.928> 1.1 enter: 3 33 | // 10.138> 1.1 handle: 2 34 | // 10.228> 1.1 handle: 3 35 | // 10.228> 1.1 result: { value: 3, delay: 300 } 36 | // 10.438> 1.1 handle: 1 37 | // 10.438> 1.1 handle: 1 38 | 39 | /** 40 | * 串行执行,通过t.inc做一个累加器,得到第一个满足条件的结果对象 41 | */ 42 | async.detectSeries(arr, function(item,callback) { 43 | log('1.2 enter: ', item.value); 44 | t.inc(item.value, function(err,n) { 45 | log('1.1 handle: ', item.value); 46 | callback(n%2===0); 47 | }, item.delay); 48 | }, function(result) { 49 | log('1.2 result: ', result); 50 | }); 51 | // 09.928> 1.2 enter: 1 52 | // 10.438> 1.2 result: { value: 1, delay: 500 } 53 | -------------------------------------------------------------------------------- /each.js: -------------------------------------------------------------------------------- 1 | var async = require('async'); 2 | 3 | var t = require('./t'); 4 | var log = t.log; 5 | 6 | /** 7 | * 如果想对同一个集合中的所有元素都执行同一个异步操作,可以利用each函数。 8 | * 9 | * async提供了三种方式: 10 | * 1. 集合中所有元素并行执行 11 | * 2. 一个一个顺序执行 12 | * 3. 分批执行,同一批内并行,批与批之间按顺序 13 | * 14 | * 如果中途出错,则错误将上传给最终的callback处理。其它已经启动的任务继续执行,未启动的忽略。 15 | */ 16 | // each(arr, iterator(item, callback), callback(err)) 17 | 18 | 19 | var arr = [{name:'Jack', delay: 200}, 20 | {name:'Mike', delay: 100}, 21 | {name:'Freewind', delay: 300}]; 22 | 23 | /** 24 | * 所有操作并发执行,且全部未出错,最终得到的err为undefined。注意最终callback只有一个参数err。 25 | */ 26 | // 1.1 27 | async.each(arr, function(item, callback) { 28 | log('1.1 enter: ' + item.name); 29 | setTimeout(function(){ 30 | log('1.1 handle: ' + item.name); 31 | callback(null, item.name); 32 | }, item.delay); 33 | }, function(err) { 34 | log('1.1 err: ' + err); 35 | }); 36 | // 输出如下: 37 | // 42.244> 1.1 enter: Jack 38 | // 42.245> 1.1 enter: Mike 39 | // 42.245> 1.1 enter: Freewind 40 | // 42.350> 1.1 handle: Mike 41 | // 42.445> 1.1 handle: Jack 42 | // 42.554> 1.1 handle: Freewind 43 | // 42.554> 1.1 err: undefined 44 | 45 | 46 | /** 47 | * 如果中途出错,则出错后马上调用最终的callback。其它未执行完的任务继续执行。 48 | */ 49 | async.each(arr,function(item, callback) { 50 | log('1.2 enter: ' +item.name); 51 | setTimeout(function() { 52 | log('1.2 handle: ' + item.name); 53 | if(item.name==='Jack') { 54 | callback('myerr'); 55 | } 56 | }, item.delay); 57 | }, function(err) { 58 | log('1.2 err: ' + err); 59 | }); 60 | // 输出如下: 61 | // 42.246> 1.2 enter: Jack 62 | // 42.246> 1.2 enter: Mike 63 | // 42.246> 1.2 enter: Freewind 64 | // 42.350> 1.2 handle: Mike 65 | // 42.445> 1.2 handle: Jack 66 | // 42.446> 1.2 err: myerr 67 | // 42.555> 1.2 handle: Freewind 68 | 69 | /** 70 | * 与each相似,但不是并行执行。而是一个个按顺序执行。 71 | */ 72 | async.eachSeries(arr, function(item, callback) { 73 | log('1.3 enter: ' + item.name); 74 | setTimeout(function(){ 75 | log('1.3 handle: ' + item.name); 76 | callback(null, item.name); 77 | }, item.delay); 78 | }, function(err) { 79 | log('1.3 err: ' + err); 80 | }); 81 | // 42.247> 1.3 enter: Jack 82 | // 42.459> 1.3 handle: Jack 83 | // 42.459> 1.3 enter: Mike 84 | // 42.569> 1.3 handle: Mike 85 | // 42.569> 1.3 enter: Freewind 86 | // 42.883> 1.3 handle: Freewind 87 | // 42.883> 1.3 err: undefined 88 | 89 | /** 90 | * 如果中途出错,则马上把错误传给最终的callback,还未执行的不再执行。 91 | */ 92 | async.eachSeries(arr,function(item, callback) { 93 | log('1.4 enter: ' +item.name); 94 | setTimeout(function() { 95 | log('1.4 handle: ' + item.name); 96 | if(item.name==='Jack') { 97 | callback('myerr'); 98 | } 99 | }, item.delay); 100 | }, function(err) { 101 | log('1.4 err: ' + err); 102 | }); 103 | // 42.247> 1.4 enter: Jack 104 | // 42.460> 1.4 handle: Jack 105 | // 42.460> 1.4 err: myerr 106 | 107 | /** 108 | * 分批执行,第二个参数是每一批的个数。每一批内并行执行,但批与批之间按顺序执行。 109 | */ 110 | async.eachLimit(arr, 2, function(item, callback) { 111 | log('1.5 enter: ' + item.name); 112 | setTimeout(function(){ 113 | log('1.5 handle: ' + item.name); 114 | callback(null, item.name); 115 | }, item.delay); 116 | }, function(err) { 117 | log('1.5 err: ' + err); 118 | }); 119 | // 42.247> 1.5 enter: Jack 120 | // 42.248> 1.5 enter: Mike 121 | // 42.351> 1.5 handle: Mike 122 | // 42.352> 1.5 enter: Freewind 123 | // 42.461> 1.5 handle: Jack 124 | // 42.664> 1.5 handle: Freewind 125 | // 42.664> 1.5 err: undefined 126 | 127 | /** 128 | * 如果中途出错,错误将马上传给最终的callback。同一批中的未执行完的任务还将继续执行,但下一批及以后的不再执行。 129 | */ 130 | async.eachLimit(arr,2,function(item, callback) { 131 | log('1.6 enter: ' +item.name); 132 | setTimeout(function() { 133 | log('1.6 handle: ' + item.name); 134 | if(item.name==='Jack') { 135 | callback('myerr'); 136 | } 137 | }, item.delay); 138 | }, function(err) { 139 | log('1.6 err: ' + err); 140 | }); 141 | // 42.248> 1.6 enter: Jack 142 | // 42.248> 1.6 enter: Mike 143 | // 42.352> 1.6 handle: Mike 144 | // 42.462> 1.6 handle: Jack 145 | // 42.462> 1.6 err: myerr -------------------------------------------------------------------------------- /every.js: -------------------------------------------------------------------------------- 1 | var async = require('async'); 2 | 3 | var t = require('./t'); 4 | var log = t.log; 5 | 6 | /** 7 | * 如果集合里每一个元素都满足条件,则传给最终回调的result为true,否则为false 8 | */ 9 | // every(arr, iterator(item,callback), callback(result)) 10 | //alias: all 11 | 12 | var arr = [1,2,3,6]; 13 | 14 | /** 15 | * 串行执行,集合中所有的元素都<=10,所以为true 16 | */ 17 | async.every(arr, function(item,callback){ 18 | log('1.1 enter: ',item); 19 | setTimeout(function(){ 20 | log('1.1 handle: ',item); 21 | callback(item<=10); 22 | },100); 23 | }, function(result) { 24 | log('1.1 result: ', result); 25 | }); 26 | // 32.113> 1.1 enter: 1 27 | // 32.123> 1.1 enter: 2 28 | // 32.123> 1.1 enter: 3 29 | // 32.123> 1.1 enter: 6 30 | // 32.233> 1.1 handle: 1 31 | // 32.233> 1.1 handle: 2 32 | // 32.233> 1.1 handle: 3 33 | // 32.233> 1.1 handle: 6 34 | // 32.233> 1.1 result: true 35 | 36 | /** 37 | * 串行执行,集合中至少有一个元素不大于2,所以为false 38 | */ 39 | async.every(arr, function(item,callback){ 40 | log('1.2 enter: ',item); 41 | setTimeout(function(){ 42 | log('1.2 handle: ',item); 43 | callback(item>2); 44 | },100); 45 | }, function(result) { 46 | log('1.2 result: ', result); 47 | }); 48 | // 32.123> 1.2 enter: 1 49 | // 32.123> 1.2 enter: 2 50 | // 32.123> 1.2 enter: 3 51 | // 32.123> 1.2 enter: 6 52 | // 32.233> 1.2 handle: 1 53 | // 32.233> 1.2 result: false 54 | // 32.233> 1.2 handle: 2 55 | // 32.233> 1.2 handle: 3 56 | // 32.233> 1.2 handle: 6 57 | -------------------------------------------------------------------------------- /filter_reject.js: -------------------------------------------------------------------------------- 1 | var async = require('async'); 2 | 3 | var t = require('./t'); 4 | var log = t.log; 5 | 6 | /** 7 | * 使用异步操作对集合中的元素进行筛选。需要注意的是,iterator的callback只有一个参数,只能接收true或false。 8 | * 9 | * 对于出错,该函数没有做出任何处理,直接由nodejs抛出。所以需要注意对Error的处理。 10 | * 11 | * async提供了两种方式: 12 | * 1. 并行执行:filter 13 | * 2. 顺序执行:filterSereis 14 | */ 15 | // filter(arr, iterator(item, callback(test)), callback(results)) 16 | 17 | var arr = [1,2,3,4,5]; 18 | 19 | /** 20 | * 并行执行,对arr进行筛选。 21 | */ 22 | async.filter(arr, function(item, callback) { 23 | log('1.1 enter: ' + item); 24 | setTimeout(function() { 25 | log('1.1 test: ' + item); 26 | callback(item>=3); 27 | }, 200); 28 | }, function(results) { 29 | log('1.1 results: ', results); 30 | }); 31 | //16.739> 1.1 enter: 1 32 | //16.749> 1.1 enter: 2 33 | //16.749> 1.1 enter: 3 34 | //16.749> 1.1 enter: 4 35 | //16.749> 1.1 enter: 5 36 | //16.749> 1.3 enter: 1 37 | //16.949> 1.1 test: 1 38 | //16.949> 1.1 test: 2 39 | //16.949> 1.1 test: 3 40 | //16.949> 1.1 test: 4 41 | //16.949> 1.1 test: 5 42 | //16.949> 1.1 results: [ 3, 4, 5 ] 43 | 44 | 45 | /** 46 | * 如果出错,将会由nodejs抛出,导致出错。为保证其它代码正常运行,注释掉该测试。 47 | * 48 | * try..catch:抓不到这个错误 49 | */ 50 | /* 51 | async.filter(arr, function(item, callback) { 52 | log('1.2 enter: ' + item); 53 | setTimeout(function() { 54 | log('1.2 handle: ' + item); 55 | if(item===2) { 56 | throw new Error('myerr'); 57 | } 58 | callback(item>=3); 59 | }, 100); 60 | }, function(results) { 61 | log('1.2 results: ', results); 62 | }); 63 | */ 64 | 65 | /** 66 | * 串行执行,对arr进行筛选。 67 | */ 68 | // 1.3 69 | async.filterSeries(arr, function(item, callback) { 70 | log('1.3 enter: ' + item); 71 | setTimeout(function() { 72 | log('1.3 handle: ' + item); 73 | callback(item>=3); 74 | }, 200); 75 | }, function(results) { 76 | log('1.3 results: ', results); 77 | }); 78 | // 16.749> 1.3 enter: 1 79 | // 16.949> 1.3 handle: 1 80 | // 16.949> 1.3 enter: 2 81 | // 17.149> 1.3 handle: 2 82 | // 17.149> 1.3 enter: 3 83 | // 17.369> 1.3 handle: 3 84 | // 17.369> 1.3 enter: 4 85 | // 17.589> 1.3 handle: 4 86 | // 17.589> 1.3 enter: 5 87 | // 17.789> 1.3 handle: 5 88 | // 17.789> 1.3 results: [ 3, 4, 5 ] 89 | 90 | 91 | /* 92 | * reject跟filter正好相反,当测试为true时,抛弃之 93 | */ 94 | // reject(arr, iterator(item, callback(test)), callback(results) 95 | async.reject(arr, function(item, callback) { 96 | log('1.4 enter: ' + item); 97 | setTimeout(function() { 98 | log('1.4 test: ' + item); 99 | callback(item>=3); 100 | }, 200); 101 | }, function(results) { 102 | log('1.4 results: ', results); 103 | }); 104 | // 31.359> 1.4 enter: 1 105 | // 31.359> 1.4 enter: 2 106 | // 31.359> 1.4 enter: 3 107 | // 31.359> 1.4 enter: 4 108 | // 31.359> 1.4 enter: 5 109 | // 31.559> 1.4 test: 1 110 | // 31.559> 1.4 test: 2 111 | // 31.559> 1.4 test: 3 112 | // 31.559> 1.4 test: 4 113 | // 31.559> 1.4 test: 5 114 | // 31.569> 1.4 results: [ 1, 2 ] 115 | 116 | 117 | /** 118 | * 串行执行,对arr进行筛选。 119 | */ 120 | // 1.3 121 | async.rejectSeries(arr, function(item, callback) { 122 | log('1.5 enter: ' + item); 123 | setTimeout(function() { 124 | log('1.5 handle: ' + item); 125 | callback(item>=3); 126 | }, 200); 127 | }, function(results) { 128 | log('1.5 results: ', results); 129 | }); 130 | //43.592> 1.5 enter: 1 131 | //43.799> 1.5 handle: 1 132 | //43.800> 1.5 enter: 2 133 | //44.004> 1.5 handle: 2 134 | //44.007> 1.5 enter: 3 135 | //44.210> 1.5 handle: 3 136 | //44.211> 1.5 enter: 4 137 | //44.412> 1.5 handle: 4 138 | //44.413> 1.5 enter: 5 139 | //44.614> 1.5 handle: 5 140 | //44.616> 1.5 results: [ 1, 2 ] -------------------------------------------------------------------------------- /iterator.js: -------------------------------------------------------------------------------- 1 | var async = require('async'); 2 | var t = require('./t'); 3 | var log = t.log; 4 | 5 | /** 6 | * 将一组函数包装成为一个iterator,初次调用此iterator时,会执行定义中的第一个函数并返回第二个函数以供调用。 7 | * 也可通过手动调用 next() 得到以下一个函数为起点的新的iterator。 8 | * 该函数通常由async在内部使用,但如果需要时,也可在我们的代码中使用它。 9 | */ 10 | // async.iterator(tasks) 11 | 12 | var iter = async.iterator([ 13 | function () {log('I am 111')}, 14 | function () {log('I am 222')}, 15 | function () {log('I am 333')} 16 | ]); 17 | 18 | /** 19 | * 直接调用(),会执行当前函数,并返回一个由下个函数为起点的新的iterator 20 | */ 21 | //1.1 22 | log('1.1 iter()'); 23 | var it1 = iter(); 24 | it1(); 25 | it1(); 26 | //28.368> 1.1 iter() 27 | //28.371> I am 111 28 | //28.372> I am 222 29 | //28.372> I am 222 30 | 31 | /** 32 | * 通过iter()来调用下一个函数 33 | */ 34 | log('1.2 iter()'); 35 | var it2 = iter(); 36 | var it3 = it2(); 37 | var it4 = it3(); 38 | //it4(); // 这句代码执行会报错 39 | log(it4); // => 'null' 40 | //32.449> 1.2 iter() 41 | //32.452> I am 111 42 | //32.452> I am 222 43 | //32.453> I am 333 44 | //32.454> null 45 | 46 | /** 47 | * 调用next(),不会执行当前函数,直接返回由下个函数为起点的新iterator 48 | * 对于同一个iterator,多次调用next(),不会影响自己 49 | */ 50 | //1.3 51 | log('1.3 iter()'); 52 | var it5 = iter.next(); 53 | it5(); 54 | var it6 = iter.next().next(); 55 | it6(); 56 | iter(); 57 | //39.895> 1.3 iter() 58 | //39.898> I am 222 59 | //39.899> I am 333 60 | //39.899> I am 111 61 | 62 | -------------------------------------------------------------------------------- /map.js: -------------------------------------------------------------------------------- 1 | var async = require('async'); 2 | 3 | var t = require('./t'); 4 | var log = t.log; 5 | 6 | /** 7 | * 对集合中的每一个元素,执行某个异步操作,得到结果。所有的结果将汇总到最终的callback里。与each的区别是,each只关心操作不管最后的值,而map关心的最后产生的值。 8 | * 9 | * 提供了两种方式: 10 | * 1. 并行执行。同时对集合中所有元素进行操作,结果汇总到最终callback里。如果出错,则立刻返回错误以及已经执行完的任务的结果,未执行完的占个空位 11 | * 2. 顺序执行。对集合中的元素一个一个执行操作,结果汇总到最终callback里。如果出错,则立刻返回错误以及已经执行完的结果,未执行的被忽略。 12 | */ 13 | // map(arr, iterator(item, callback), callback(err, results)) 14 | 15 | var arr = [{name:'Jack', delay:200}, {name:'Mike', delay: 100}, {name:'Freewind', delay:300}, {name:'Test', delay: 50}]; 16 | 17 | /** 18 | * 所有操作均正确执行,未出错。所有结果按元素顺序汇总给最终的callback。 19 | */ 20 | // 1.1 21 | async.map(arr, function(item, callback) { 22 | log('1.1 enter: ' + item.name); 23 | setTimeout(function() { 24 | log('1.1 handle: ' + item.name); 25 | callback(null, item.name + '!!!'); 26 | }, item.delay); 27 | }, function(err,results) { 28 | log('1.1 err: ', err); 29 | log('1.1 results: ', results); 30 | }); 31 | // 54.569> 1.1 enter: Jack 32 | // 54.569> 1.1 enter: Mike 33 | // 54.569> 1.1 enter: Freewind 34 | // 54.569> 1.1 enter: Test 35 | // 54.629> 1.1 handle: Test 36 | // 54.679> 1.1 handle: Mike 37 | // 54.789> 1.1 handle: Jack 38 | // 54.879> 1.1 handle: Freewind 39 | // 54.879> 1.1 err: 40 | // 54.879> 1.1 results: [ 'Jack!!!', 'Mike!!!', 'Freewind!!!', 'Test!!!' ] 41 | 42 | /** 43 | * 如果中途出错,立刻将错误、以及已经执行完成的结果汇总给最终callback。未执行完的将会在结果数组中用占个空位。 44 | */ 45 | async.map(arr, function(item, callback) { 46 | log('1.2 enter: ' + item.name); 47 | setTimeout(function() { 48 | log('1.2 handle: ' + item.name); 49 | if(item.name==='Jack') callback('myerr'); 50 | else callback(null, item.name+'!!!'); 51 | }, item.delay); 52 | }, function(err, results) { 53 | log('1.2 err: ', err); 54 | log('1.2 results: ', results); 55 | }); 56 | // 54.569> 1.2 enter: Jack 57 | // 54.569> 1.2 enter: Mike 58 | // 54.569> 1.2 enter: Freewind 59 | // 54.569> 1.2 enter: Test 60 | // 54.629> 1.2 handle: Test 61 | // 54.679> 1.2 handle: Mike 62 | // 54.789> 1.2 handle: Jack 63 | // 54.789> 1.2 err: myerr 64 | // 54.789> 1.2 results: [ undefined, 'Mike!!!', , 'Test!!!' ] 65 | // 54.879> 1.2 handle: Freewind 66 | 67 | /** 68 | * 顺序执行,一个完了才执行下一个。 69 | */ 70 | async.mapSeries(arr, function(item, callback) { 71 | log('1.3 enter: ' + item.name); 72 | setTimeout(function() { 73 | log('1.3 handle: ' + item.name); 74 | callback(null, item.name+'!!!'); 75 | }, item.delay); 76 | }, function(err,results) { 77 | log('1.3 err: ', err); 78 | log('1.3 results: ', results); 79 | }); 80 | // 54.569> 1.3 enter: Jack 81 | // 54.789> 1.3 handle: Jack 82 | // 54.789> 1.3 enter: Mike 83 | // 54.899> 1.3 handle: Mike 84 | // 54.899> 1.3 enter: Freewind 85 | // 55.209> 1.3 handle: Freewind 86 | // 55.209> 1.3 enter: Test 87 | // 55.269> 1.3 handle: Test 88 | // 55.269> 1.3 err: 89 | // 55.269> 1.3 results: [ 'Jack!!!', 'Mike!!!', 'Freewind!!!', 'Test!!!' ] 90 | 91 | /** 92 | * 顺序执行过程中出错,只把错误以及执行完的传给最终callback,未执行的忽略。 93 | */ 94 | async.mapSeries(arr, function(item, callback) { 95 | log('1.4 enter: ' + item.name); 96 | setTimeout(function() { 97 | log('1.4 handle: ' + item.name); 98 | if(item.name==='Mike') callback('myerr'); 99 | else callback(null, item.name+'!!!'); 100 | }, item.delay); 101 | }, function(err, results) { 102 | log('1.4 err: ', err); 103 | log('1.4 results: ', results); 104 | }); 105 | // 47.616> 1.4 enter: Jack 106 | // 47.821> 1.4 handle: Jack 107 | // 47.821> 1.4 enter: Mike 108 | // 47.931> 1.4 handle: Mike 109 | // 47.931> 1.4 err: myerr 110 | // 47.932> 1.4 results: [ 'Jack!!!', undefined ] 111 | 112 | /** 113 | * 并行执行,同时最多2个函数并行,传给最终callback。 114 | */ 115 | //1.5 116 | async.mapLimit(arr,2, function(item, callback) { 117 | log('1.5 enter: ' + item.name); 118 | setTimeout(function() { 119 | log('1.5 handle: ' + item.name); 120 | if(item.name==='Jack') callback('myerr'); 121 | else callback(null, item.name+'!!!'); 122 | }, item.delay); 123 | }, function(err, results) { 124 | log('1.5 err: ', err); 125 | log('1.5 results: ', results); 126 | }); 127 | //57.797> 1.5 enter: Jack 128 | //57.800> 1.5 enter: Mike 129 | //57.900> 1.5 handle: Mike 130 | //57.900> 1.5 enter: Freewind 131 | //58.008> 1.5 handle: Jack 132 | //58.009> 1.5 err: myerr 133 | //58.009> 1.5 results: [ undefined, 'Mike!!!' ] 134 | //58.208> 1.5 handle: Freewind 135 | //58.208> 1.5 enter: Test 136 | //58.273> 1.5 handle: Test 137 | -------------------------------------------------------------------------------- /nextTick.js: -------------------------------------------------------------------------------- 1 | var async = require('async'); 2 | var t = require('./t'); 3 | var log = t.log; 4 | 5 | /** 6 | * nextTick的作用与nodejs的nextTick一样,再最后调用函数。 7 | * 但在浏览器端,只能使用setTimeout(callback,0),但这个方法有时候会让其它高优先级的任务插到前面去。 8 | * 所以提供了这个nextTick,让同样的代码在服务器端和浏览器端表现一致。 9 | */ 10 | // nextTick(callback) 11 | 12 | var calls = []; 13 | async.nextTick(function() { 14 | calls.push('two'); 15 | }); 16 | async.nextTick(function() { 17 | log('1.1',calls); 18 | }); 19 | calls.push('one'); 20 | log('1.2',calls); 21 | async.nextTick(function() { 22 | log('1.3',calls); 23 | }); 24 | //09.838> 1.2[ 'one' ] 25 | //09.842> 1.1[ 'one', 'two' ] 26 | //09.843> 1.3[ 'one', 'two' ] 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "async_demo", 3 | "version": "0.1.1", 4 | "private": true, 5 | "dependencies": { 6 | "moment": "*", 7 | "async": "*" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /parallel.js: -------------------------------------------------------------------------------- 1 | var async = require('async'); 2 | var t = require('./t'); 3 | var log = t.log; 4 | 5 | /** 6 | * 并行执行多个函数,每个函数都是立即执行,不需要等待其它函数先执行。传给最终callback的数组中的数据按照tasks中声明的顺序,而不是执行完成的顺序。 7 | * 8 | * 如果某个函数出错,则立刻将err和已经执行完的函数的结果值传给parallel最终的callback。其它未执行完的函数的值不会传到最终数据,但要占个位置。 9 | * 同时支持json形式的tasks,其最终callback的结果也为json形式。 10 | */ 11 | // parallel(tasks, [callback]) 12 | 13 | /** 14 | * 并行执行多个函数,每个函数的值将按函数声明的先后顺序汇成一个数组,传给最终callback。 15 | */ 16 | // 1.1 17 | async.parallel([ 18 | function(cb) { t.fire('a400', cb, 400) }, 19 | function(cb) { t.fire('a200', cb, 200) }, 20 | function(cb) { t.fire('a300', cb, 300) } 21 | ], function (err, results) { 22 | log('1.1 err: ', err); 23 | log('1.1 results: ', results); 24 | }); 25 | //36.929> 1.1 err: null 26 | //36.930> 1.1 results: [ 'a400', 'a200', 'a300' ] 27 | 28 | /** 29 | * 如果中途有个函数出错,则将该err和已经完成的函数值汇成一个数组,传给最终的callback。还没有执行完的函数的值将被忽略,但要在最终数组中占个位置 30 | */ 31 | // 1.2 32 | async.parallel([ 33 | function(cb) { log('1.2.1: ', 'start'); t.fire('a400', cb, 400) }, // 该函数的值不会传给最终callback,但要占个位置 34 | function(cb) { log('1.2.2: ', 'start'); t.err('e200', cb, 200) }, 35 | function(cb) { log('1.2.3: ', 'start'); t.fire('a100', cb, 100) } 36 | ], function(err, results) { 37 | log('1.2 err: ', err); 38 | log('1.2 results: ', results); 39 | }); 40 | //36.537> 1.2.1: start 41 | //36.540> 1.2.2: start 42 | //36.541> 1.2.3: start 43 | //36.741> 1.2 err: e200 44 | //36.744> 1.2 results: [ , undefined, 'a100' ] 45 | 46 | /** 47 | * 以json形式传入tasks,最终results也为json 48 | */ 49 | // 1.3 50 | async.parallel({ 51 | a: function(cb) { t.fire('a400', cb, 400) }, 52 | b: function(cb) { t.fire('c300', cb, 300) } 53 | }, function(err, results) { 54 | log('1.3 err: ', err); 55 | log('1.3 results: ', results); 56 | }); 57 | //36.943> 1.3 err: null 58 | //36.944> 1.3 results: { b: 'c300', a: 'a400' } 59 | 60 | /** 61 | * 如果中途出错,会将err与已经完成的函数值(汇成一个json)传给最终callback。未执行完成的函数值被忽略,不会出现在最终json中。 62 | */ 63 | // 1.4 64 | async.parallel({ 65 | a: function(cb) { t.fire('a400', cb, 400) }, // 该函数的值不会传给最终的callback 66 | b: function(cb) { t.err('e300', cb, 300) }, 67 | c: function(cb) { t.fire('c200', cb, 200) } 68 | }, function(err, results) { 69 | log('1.4 err: ', err); 70 | log('1.4 results: ', results); 71 | }); 72 | //36.853> 1.4 err: e300 73 | //36.854> 1.4 results: { c: 'c200', b: undefined } 74 | 75 | /** 76 | * 并行执行,同时最多2个函数并行,传给最终callback。 77 | */ 78 | //1.5 79 | async.parallelLimit({ 80 | a:function(cb) { log('a start'); t.fire('a400', cb, 200) }, 81 | b:function(cb) { log('b start'); t.fire('b200', cb, 200) }, 82 | c:function(cb) { log('c start'); t.fire('c100', cb, 100) }, 83 | d:function(cb) { log('d start'); t.fire('d600', cb, 600) }, 84 | e:function(cb) { log('e start'); t.fire('e300', cb, 300) } 85 | },2, function(err, results) { 86 | log('1.5 err: ', err); 87 | log('1.5 results: ', results); 88 | }); 89 | //26.993> a start 90 | //26.996> b start 91 | //27.200> c start 92 | //27.202> d start 93 | //27.313> e start 94 | //27.809> 1.5 err: 95 | //27.810> 1.5 results: { a: 'a400', b: 'b200', c: 'c100', e: 'e300', d: 'd600' } -------------------------------------------------------------------------------- /queue.js: -------------------------------------------------------------------------------- 1 | var async = require('async'); 2 | var t = require('./t'); 3 | var log = t.log; 4 | 5 | /** 6 | * queue是一个串行的消息队列,通过限制了worker数量,不再一次性全部执行。 7 | * 当worker数量不够用时,新加入的任务将会排队等候,直到有新的worker可用。 8 | * 9 | * 该函数有多个点可供回调,如worker用完时、无等候任务时、全部执行完时等。 10 | */ 11 | // queue(worker, concurrency) 12 | 13 | /** 14 | * 定义一个queue,设worker数量为2 15 | */ 16 | var q = async.queue(function(task, callback) { 17 | log('worker is processing task: ', task.name); 18 | task.run(callback); 19 | }, 2); 20 | 21 | /** 22 | * 监听:如果某次push操作后,任务数将达到或超过worker数量时,将调用该函数 23 | */ 24 | q.saturated = function() { 25 | log('all workers to be used'); 26 | } 27 | 28 | /** 29 | * 监听:当最后一个任务交给worker时,将调用该函数 30 | */ 31 | q.empty = function() { 32 | log('no more tasks wating'); 33 | } 34 | 35 | /** 36 | * 监听:当所有任务都执行完以后,将调用该函数 37 | */ 38 | q.drain = function() { 39 | log('all tasks have been processed'); 40 | } 41 | 42 | /** 43 | * 独立加入2个任务 44 | */ 45 | q.push({name:'t1', run: function(cb){ 46 | log('t1 is running, waiting tasks: ', q.length()); 47 | t.fire('t1', cb, 400); // 400ms后执行 48 | }}, function(err) { 49 | log('t1 executed'); 50 | }); 51 | log('pushed t1, waiting tasks: ', q.length()); 52 | 53 | q.push({name:'t2',run: function(cb){ 54 | log('t2 is running, waiting tasks: ', q.length()); 55 | t.fire('t2', cb, 200); // 200ms后执行 56 | }}, function(err) { 57 | log('t2 executed'); 58 | }); 59 | log('pushed t2, waiting tasks: ', q.length()); 60 | //54.448> pushed t1, waiting tasks: 1 61 | //54.451> all workers to be used 62 | //54.452> pushed t2, waiting tasks: 2 63 | //54.452> worker is processing task: t1 64 | //54.453> t1 is running, waiting tasks: 1 65 | //54.455> no more tasks wating 66 | //54.455> worker is processing task: t2 67 | //54.455> t2 is running, waiting tasks: 0 68 | //54.656> t2 executed 69 | //54.867> t1 executed 70 | //54.868> all tasks have been processed 71 | 72 | 73 | // 同时加入多个任务 74 | q.push([ 75 | { 76 | name:'t3', run: function(cb){ 77 | log('t3 is running, waiting tasks: ', q.length()); 78 | t.fire('t3', cb, 300); // 300ms后执行 79 | } 80 | },{ 81 | name:'t4', run: function(cb){ 82 | log('t4 is running, waiting tasks: ', q.length()); 83 | t.fire('t4', cb, 500); // 500ms后执行 84 | } 85 | },{ 86 | name:'t5', run: function(cb){ 87 | log('t5 is running, waiting tasks: ', q.length()); 88 | t.fire('t5', cb, 100); // 100ms后执行 89 | } 90 | },{ 91 | name:'t6', run: function(cb){ 92 | log('t6 is running, waiting tasks: ', q.length()); 93 | t.fire('t6', cb, 400); // 400ms后执行 94 | } 95 | } 96 | ], function(err) { 97 | log('err: ',err); 98 | }); 99 | log('pushed t3,t4,t5,t6 into queue, waiting tasks: ', q.length()); 100 | //53.755> all workers to be used 101 | //53.758> pushed t3,t4,t5,t6 into queue, waiting tasks: 4 102 | //53.759> worker is processing task: t3 103 | //53.760> t3 is running, waiting tasks: 3 104 | //53.762> worker is processing task: t4 105 | //53.762> t4 is running, waiting tasks: 2 106 | //54.073> err: null 107 | //54.074> worker is processing task: t5 108 | //54.076> t5 is running, waiting tasks: 1 109 | //54.183> err: null 110 | //54.184> no more tasks wating 111 | //54.185> worker is processing task: t6 112 | //54.186> t6 is running, waiting tasks: 0 113 | //54.265> err: null 114 | //54.588> err: null 115 | //54.589> all tasks have been processed 116 | 117 | -------------------------------------------------------------------------------- /reduce.js: -------------------------------------------------------------------------------- 1 | var async = require('async'); 2 | 3 | var t = require('./t'); 4 | var log = t.log; 5 | 6 | /** 7 | * Reduce可以让我们给定一个初始值,用它与集合中的每一个元素做运算,最后得到一个值。reduce从左向右来遍历元素,如果想从右向左,可使用reduceRight。 8 | */ 9 | //reduce(arr, memo, iterator(memo,item,callback), callback(err,result)) 10 | //alias: inject, foldl 11 | 12 | var arr = [1,3,5]; 13 | 14 | /** 15 | * 顺序执行 16 | */ 17 | async.reduce(arr, 100, function(memo, item, callback) { 18 | log('1.1 enter: ' + memo +', ' + item); 19 | setTimeout(function() { 20 | callback(null, memo+item); 21 | }, 100); 22 | },function(err, result) { 23 | log('1.1 err: ', err); 24 | log('1.1 result: ', result); 25 | }); 26 | // 28.789> 1.1 enter: 100, 1 27 | // 28.889> 1.1 enter: 101, 3 28 | // 28.999> 1.1 enter: 104, 5 29 | // 29.109> 1.1 err: 30 | // 29.109> 1.1 result: 109 31 | 32 | /** 33 | * 顺序执行过程中出错,只把错误传给最终callback,结果是null 34 | */ 35 | async.reduce(arr, 100, function(memo, item, callback) { 36 | log('1.2 enter: ' + memo +', ' + item); 37 | setTimeout(function() { 38 | if(item===3) callback('myerr'); 39 | else callback(null, memo+item); 40 | }, 100); 41 | },function(err, result) { 42 | log('1.2 err: ', err); 43 | log('1.2 result: ', result); 44 | }); 45 | // 05.541> 1.2 enter: 100, 1 46 | // 05.649> 1.2 enter: 101, 3 47 | // 05.760> 1.2 err: myerr 48 | // 05.760> 1.2 result: 49 | 50 | /** 51 | * 顺序执行从右向左 52 | * 53 | * alias: foldr 54 | */ 55 | async.reduceRight(arr, 100, function(memo, item, callback) { 56 | log('1.3 enter: ' + memo +', ' + item); 57 | setTimeout(function() { 58 | callback(null, memo+item); 59 | }, 100); 60 | },function(err, result) { 61 | log('1.3 err: ', err); 62 | log('1.3 result: ', result); 63 | }); 64 | // 28.789> 1.3 enter: 100, 5 65 | // 28.889> 1.3 enter: 105, 3 66 | // 28.999> 1.3 enter: 108, 1 67 | // 29.109> 1.3 err: 68 | // 29.109> 1.3 result: 109 69 | 70 | /** 71 | * 通过t.inc做一个累加器,参与reduce的计算 72 | */ 73 | async.reduce(arr, 100, function(memo,item,callback) { 74 | log('1.4 enter: '+memo+','+item); 75 | t.inc(item, function(err,n) { 76 | log('1.4 handle: ',n); 77 | callback(null, memo+n); 78 | }); 79 | }, function(err,result) { 80 | log('1.4 err: ', err); 81 | log('1.4 result: ', result); 82 | }); 83 | // 28.789> 1.4 enter: 100,1 84 | // 28.999> 1.4 handle: 2 85 | // 28.999> 1.4 enter: 102,3 86 | // 29.209> 1.4 handle: 4 87 | // 29.209> 1.4 enter: 106,5 88 | // 29.409> 1.4 handle: 6 89 | // 29.409> 1.4 err: 90 | // 29.409> 1.4 result: 112 91 | // --> spent 0.62s 92 | 93 | /** 94 | * 通过t.inc做一个累加器,并实现对map的结果集做reduce 95 | */ 96 | async.map(arr, function(item, callback) { 97 | log('1.5 enter: ', item); 98 | t.inc(item, function(err,n){ 99 | log('1.5 handle: ', n); 100 | callback(null,n); 101 | }); 102 | },function(err, results) { 103 | log('1.5 err: ', err); 104 | log('1.5 results: ', results); 105 | var sum = results.reduce(function(memo, item) { 106 | return memo + item; 107 | }, 100); 108 | log('1.5 sum: ', sum); 109 | }); 110 | // 28.789> 1.5 enter: 1 111 | // 28.789> 1.5 enter: 3 112 | // 28.789> 1.5 enter: 5 113 | // 28.999> 1.5 handle: 2 114 | // 28.999> 1.5 handle: 4 115 | // 28.999> 1.5 handle: 6 116 | // 28.999> 1.5 err: 117 | // 28.999> 1.5 results: [ 2, 4, 6 ] 118 | // 28.999> 1.5 sum: 112 119 | // --> spent 0.21 -------------------------------------------------------------------------------- /series.js: -------------------------------------------------------------------------------- 1 | var async = require('async'); 2 | 3 | var t = require('./t'); 4 | var log = t.log; 5 | 6 | /** 7 | * 串行执行,一个函数数组中的每个函数,每一个函数执行完成之后才能执行下一个函数。 8 | * 9 | * 如果任何一个函数向它的回调函数中传了一个error,则后面的函数都不会被执行,并且会立刻将该error以及已经执行了的函数的结果,传给series中最后那个callback。 10 | * 当所有的函数执行完后(没有出错),则会把每个函数传给其回调函数的结果合并为一个数组,传给series最后的那个callback。 11 | * 还可以json的形式来提供tasks。每一个属性都会被当作函数来执行,并且结果也会以json形式传给series最后的那个callback。这种方式可读性更高一些。 12 | */ 13 | // series(tasks, [callback]) 14 | 15 | /** 16 | * 全部函数都正常执行。每个函数产生的值将按顺序合并为一个数组,传给最终的callback。 17 | */ 18 | // 1.1 19 | async.series([ 20 | function(cb) { t.inc(3, cb); }, 21 | function(cb) { t.inc(8, cb); }, 22 | function(cb) { t.inc(2, cb); } 23 | ], function(err, results) { 24 | log('1.1 err: ', err); 25 | log('1.1 results: ', results); 26 | }); 27 | //05.155> 1.1 err: null 28 | //05.156> 1.1 results: [ 4, 9, 3 ] 29 | 30 | /** 31 | * 中间有函数出错。出错之后的函数不会执行,错误及之前正常执行的函数结果将传给最终的callback。 32 | */ 33 | // 1.2 34 | async.series([ 35 | function(cb) { t.inc(3, cb); }, 36 | function(cb) { t.err('test_err', cb); }, 37 | function(cb) { t.inc(8, cb); } 38 | ], function (err, results) { 39 | log('1.2 err: ', err); 40 | log('1.2 results: ', results); 41 | }); 42 | //04.964> 1.2 err: test_err 43 | //04.973> 1.2 results: [ 4, undefined ] 44 | 45 | /** 46 | * 如果某个函数传的数据是undefined, null, {}, []等,它们会原样传给最终callback。 47 | */ 48 | // 1.3 49 | async.series([ 50 | function(cb) { t.fire(3, cb);}, 51 | function(cb) { t.fire(undefined, cb); }, 52 | function(cb) { t.fire(null, cb); }, 53 | function(cb) { t.fire({}, cb); }, 54 | function(cb) { t.fire([], cb); }, 55 | function(cb) { t.fire('abc', cb) } 56 | ], function(err, results) { 57 | log('1.3 err: ', err); 58 | log('1.3 results: ', results); 59 | }); 60 | //05.794> 1.3 err: null 61 | //05.795> 1.3 results: [ 3, undefined, null, {}, [], 'abc' ] 62 | 63 | /** 64 | * 以json形式传入tasks。其结果也将以json形式传给最终callback。 65 | */ 66 | async.series({ 67 | a: function(cb) { t.inc(3, cb); }, 68 | b: function(cb) { t.fire(undefined, cb); }, 69 | c: function (cb) { t.err('myerr', cb); }, 70 | d: function (cb) { t.inc(8, cb); } 71 | }, function (err, results) { 72 | log('1.4 err: ', err); 73 | log('1.4 results: ', results); 74 | }); 75 | //05.178> 1.4 err: myerr 76 | //05.179> 1.4 results: { a: 4, b: undefined, c: undefined } -------------------------------------------------------------------------------- /some.js: -------------------------------------------------------------------------------- 1 | var async = require('async'); 2 | 3 | var t = require('./t'); 4 | var log = t.log; 5 | 6 | /** 7 | * 当集合中是否有至少一个元素满足条件时,最终callback得到的值为true,否则为false. 8 | */ 9 | // some(arr, iterator(item,callback(test)), callback(result)) 10 | //alias: any 11 | 12 | var arr = [1,2,3,6]; 13 | 14 | /** 15 | * 串行执行,集合中至少有一个元素<=3,所以结果为true 16 | */ 17 | // 1.1 18 | async.some(arr, function(item,callback){ 19 | log('1.1 enter: ',item); 20 | setTimeout(function(){ 21 | log('1.1 handle: ',item); 22 | callback(item<=3); 23 | },100); 24 | }, function(result) { 25 | log('1.1 result: ', result); 26 | }); 27 | // 36.165> 1.1 enter: 1 28 | // 36.165> 1.1 enter: 2 29 | // 36.165> 1.1 enter: 3 30 | // 36.165> 1.1 enter: 6 31 | // 36.275> 1.1 handle: 1 32 | // 36.275> 1.1 result: true 33 | // 36.275> 1.1 handle: 2 34 | // 36.275> 1.1 handle: 3 35 | // 36.275> 1.1 handle: 6 36 | 37 | 38 | /** 39 | * 串行执行,集合中没有一个元素>10,所以结果为false 40 | */ 41 | async.some(arr, function(item,callback){ 42 | log('1.2 enter: ',item); 43 | setTimeout(function(){ 44 | log('1.2 handle: ',item); 45 | callback(item>10); 46 | },100); 47 | }, function(result) { 48 | log('1.2 result: ', result); 49 | }); 50 | // 36.165> 1.2 enter: 1 51 | // 36.165> 1.2 enter: 2 52 | // 36.165> 1.2 enter: 3 53 | // 36.165> 1.2 enter: 6 54 | // 36.275> 1.2 handle: 1 55 | // 36.275> 1.2 handle: 2 56 | // 36.275> 1.2 handle: 3 57 | // 36.275> 1.2 handle: 6 58 | // 36.275> 1.2 result: false 59 | -------------------------------------------------------------------------------- /sortBy.js: -------------------------------------------------------------------------------- 1 | var async = require('async'); 2 | 3 | var t = require('./t'); 4 | var log = t.log; 5 | 6 | /** 7 | * 对集合内的元素进行排序,依据每个元素进行某异步操作后产生的值,从小到大排序。 8 | */ 9 | // sortBy(array, iterator(item,callback(err,result)), callback(err,results)) 10 | 11 | var arr = [3,6,1]; 12 | 13 | /** 14 | * 通过异步迭代器,对集合进行排序 15 | */ 16 | async.sortBy(arr, function(item, callback) { 17 | setTimeout(function() { 18 | callback(null,item); 19 | }, 200); 20 | }, function(err,results) { 21 | log('1.1 err: ', err); 22 | log('1.1 results: ', results); 23 | }); 24 | // 26.562> 1.1 err: null 25 | // 26.562> 1.1 results: [ 1, 3, 6 ] 26 | 27 | /** 28 | * 迭代出错,callback返回err,没有results 29 | */ 30 | async.sortBy(arr, function(item, callback) { 31 | setTimeout(function() { 32 | if(item===6) callback('myerr'); 33 | else callback(null,item); 34 | }, 200); 35 | }, function(err,results) { 36 | log('1.2 err: ', err); 37 | log('1.2 results: ', results); 38 | }); 39 | // 26.572> 1.2 err: myerr 40 | // 26.572> 1.2 results: 41 | -------------------------------------------------------------------------------- /t.js: -------------------------------------------------------------------------------- 1 | // 其实这个文件名的't'我不是很明白原作者freewind的意思,我觉得叫做'lib.js'或者 2 | // 'helper.js'比较合适,因为这里面都是些辅助函数。 3 | 4 | var moment = require('moment'); 5 | 6 | exports.inc = function(n, callback, timeout) { 7 | //将参数n自增1之后的结果返回给async 8 | timeout = timeout || 200; 9 | setTimeout(function() { 10 | callback(null, n+1); 11 | }, timeout); 12 | }; 13 | 14 | exports.fire = function(obj, callback, timeout) { 15 | //直接将obj的内容返回给async 16 | timeout = timeout || 200; 17 | setTimeout(function() { 18 | callback(null, obj); 19 | }, timeout); 20 | }; 21 | 22 | exports.err = function(errMsg, callback, timeout) { 23 | //模拟一个错误的产生,让async各个函数末尾的callback接收到。 24 | timeout = timeout || 200; 25 | setTimeout(function() { 26 | callback(errMsg); 27 | }, timeout); 28 | }; 29 | 30 | // utils 31 | exports.log = function(msg, obj) { 32 | //对console.log进行了封装。主要是增加了秒钟的输出,通过秒数的差值方便大家对async的理解。 33 | process.stdout.write(moment().format('ss.SSS')+'> '); 34 | if(obj!==undefined) { 35 | process.stdout.write(msg); 36 | console.log(obj); 37 | } else { 38 | console.log(msg); 39 | } 40 | }; 41 | 42 | exports.wait = function(mils) { 43 | //刻意等待mils的时间,mils的单位是毫秒。 44 | var now = new Date; 45 | while(new Date - now <= mils); 46 | } 47 | -------------------------------------------------------------------------------- /times.js: -------------------------------------------------------------------------------- 1 | var async = require('async'); 2 | var t = require('./t'); 3 | var log = t.log; 4 | 5 | /** 6 | * 异步运行,times可以指定调用几次,并把结果合并到数组中返回 7 | */ 8 | // times(n, callback) 9 | 10 | function delay(n){return (n+12) % 7 *100;} 11 | var createUser = function(id, callback) { 12 | callback(null, { 13 | id: 'user' + id, 14 | delay:delay(id) 15 | }) 16 | } 17 | 18 | /** 19 | * 异步执行,调用3次createUser函数,结果被合并到数组返回 20 | */ 21 | //1.1 22 | async.times(3, function(n, callback){ 23 | log("1.1 enter: "+ n); 24 | setTimeout(function(){ 25 | log('1.1 handler: ',n); 26 | createUser(n, function(err, user) { 27 | callback(err, user) 28 | }) 29 | },delay(n)); 30 | }, function(err, users) { 31 | log('1.1 err: ',err); 32 | log('1.1 result: ',users); 33 | }); 34 | //07.397> 1.1 enter: 0 35 | //07.400> 1.1 enter: 1 36 | //07.401> 1.1 enter: 2 37 | //07.412> 1.1 handler: 2 38 | //07.912> 1.1 handler: 0 39 | //08.009> 1.1 handler: 1 40 | //08.010> 1.1 err: null 41 | //08.011> 1.1 result: [ { id: 'user0', delay: 500 }, 42 | // { id: 'user1', delay: 600 }, 43 | // { id: 'user2', delay: 0 } ] 44 | 45 | /** 46 | * timesSeries与time唯一不同的是,同步执行 47 | */ 48 | //timesSeries(n, callback) 49 | 50 | /** 51 | * 同步执行,调用3次createUser函数,结果被合并到数组返回 52 | */ 53 | //1.2 54 | async.timesSeries(3, function(n, callback){ 55 | log("1.2 enter: "+ n); 56 | setTimeout(function(){ 57 | log('1.2 handler: ',n); 58 | createUser(n, function(err, user) { 59 | callback(err, user) 60 | }) 61 | },delay(n)); 62 | }, function(err, users) { 63 | log('1.2 err: ',err); 64 | log('1.2 result: ',users); 65 | }); 66 | //16.642> 1.2 enter: 0 67 | //17.159> 1.2 handler: 0 68 | //17.162> 1.2 enter: 1 69 | //17.763> 1.2 handler: 1 70 | //17.767> 1.2 enter: 2 71 | //17.778> 1.2 handler: 2 72 | //17.779> 1.2 err: null 73 | //17.780> 1.2 result: [ { id: 'user0', delay: 500 }, 74 | // { id: 'user1', delay: 600 }, 75 | // { id: 'user2', delay: 0 } ] -------------------------------------------------------------------------------- /utils.js: -------------------------------------------------------------------------------- 1 | var async = require('async'); 2 | var t = require('./t'); 3 | var log = t.log; 4 | 5 | /** 6 | * 让某一个函数在内存中缓存它的计算结果。对于相同的参数,只计算一次,下次就直接拿到之前算好的结果。 7 | * hasher可以让我们自定义如何根据参数来判断它是否已经在缓存中了。 8 | */ 9 | // memoize(fn, [hasher]) 10 | //1.1 11 | var slow_fn = function(x, y, callback) { 12 | log('1.1 start working for: ' + x+','+y); 13 | t.wait(500); 14 | log('1.1 finished: ' + x+','+y); 15 | callback(null, x+','+y); 16 | }; 17 | var fn = async.memoize(slow_fn,function(x,y) { 18 | return x+y; 19 | }); 20 | fn('a','b', function(err, result) { 21 | log("1.1 first time: "+result); 22 | }); 23 | fn('cc','d', function(err, result) { 24 | log("1.1 first time: "+result); 25 | }); 26 | fn('a','b', function(err, result) { 27 | log("1.1 second time: "+result); 28 | }); 29 | //15.416> 1.1 start working for: a,b 30 | //15.920> 1.1 finished: a,b 31 | //15.920> 1.1 first time: a,b 32 | //15.921> 1.1 start working for: cc,d 33 | //16.423> 1.1 finished: cc,d 34 | //16.423> 1.1 first time: cc,d 35 | //16.424> 1.1 second time: a,b 36 | 37 | 38 | /** 39 | * 让已经被缓存的函数,返回不缓存的函数引用。 40 | */ 41 | // unmemoize(fn) 42 | //1.2 43 | var slow_fn2 = function(x, y, callback) { 44 | log('1.2 start working for: ' + x+','+y); 45 | t.wait(500); 46 | log('1.2 finished: ' + x+','+y); 47 | callback(null, x+','+y); 48 | }; 49 | var fn2 = async.memoize(slow_fn2,function(x,y) { 50 | return x+y; 51 | }); 52 | 53 | fn2('a','b', function(err,result) { 54 | log("1.2 first time: "+result); 55 | }); 56 | 57 | var unFn2 =async.unmemoize(fn2); 58 | log('1.2 unmemoized'); 59 | 60 | unFn2('a','b', function(err,result) { 61 | log("1.2 second time: "+result); 62 | }); 63 | //16.424> 1.2 start working for: a,b 64 | //16.926> 1.2 finished: a,b 65 | //16.926> 1.2 first time: a,b 66 | //16.927> 1.2 unmemoized 67 | //16.927> 1.2 start working for: a,b 68 | //17.428> 1.2 finished: a,b 69 | //17.428> 1.2 second time: a,b 70 | 71 | /** 72 | * 执行某异步函数,并记录它的返回值。试验函数时很方便,不用写那些固定模式的代码。 73 | * 如果该函数向回调中传入了多个参数,则每行记录一个。 74 | */ 75 | // log(function, arguments) 76 | //1.3 77 | var x = function() { 78 | this.name = 'bsspirit'; 79 | } 80 | var hello = function(name, callback) { 81 | setTimeout(function() { 82 | callback(null, 83 | 'first ' + name, 84 | 'second '+ name, 85 | x, 86 | {a:'123'} 87 | ); 88 | }, 200); 89 | }; 90 | log("1.3 handler"); 91 | async.log(hello, 'time'); 92 | //37.620> 1.3 handler 93 | //first time 94 | //second time 95 | //[Function] 96 | //{ a: '123' } 97 | 98 | /** 99 | * dir与log都是打印出输,在nodejs环境中没有分别。 100 | * dir的不同之处在于,会调用浏览器的console.dir()函数,显示为DOM视图。 101 | * 102 | * http://stackoverflow.com/questions/10636866/whats-the-difference-between-async-log-and-async-dir 103 | */ 104 | //1.4 105 | log("1.4 handler"); 106 | async.dir(hello, 'world'); 107 | //37.620> 1.4 handler 108 | //first time 109 | //second time 110 | //[Function] 111 | //{ a: '123' } 112 | 113 | /** 114 | * noConflict()仅仅用于浏览器端,在nodejs中没用,这里无法演示。 115 | * 116 | * 它的作用是:如果之前已经在全局域中定义了async变量,当导入本async.js时,会先把之前的async变量保存起来,然后覆盖它。 117 | * 用完之后,调用noConflict()方法,就会归还该值。同时返回async本身供换名使用。 118 | */ 119 | // noConflict() 120 | /* 121 | // global on the server, window in the browser 122 | var root = this, 123 | previous_async = root.async; 124 | 125 | if (typeof module !== 'undefined' && module.exports) { 126 | module.exports = async; 127 | } 128 | else { 129 | root.async = async; 130 | } 131 | 132 | async.noConflict = function () { 133 | root.async = previous_async; 134 | return async; 135 | }; 136 | */ -------------------------------------------------------------------------------- /waterfall.js: -------------------------------------------------------------------------------- 1 | var async = require('async'); 2 | var t = require('./t'); 3 | var log = t.log; 4 | 5 | /** 6 | * 按顺序依次执行一组函数。每个函数产生的值,都将传给下一个。 7 | * 如果中途出错,后面的函数将不会被执行。错误信息将传给waterfall最终的callback。之前产生的结果被丢弃。 8 | * 9 | * 这个函数名为waterfall(瀑布),可以想像瀑布从上到下,中途冲过一层层突起的石头。 10 | * 11 | * 注意,该函数不支持json格式的tasks 12 | */ 13 | // async.waterfall(tasks, [callback]); 14 | 15 | /** 16 | * 所有函数正常执行,每个函数的结果都将变为下一个函数的参数。 17 | * 18 | * 注意,所有的callback都必须形如callback(err, result),但err参数在前面各函数中无需声明,它被自动处理。 19 | */ 20 | // 1.1 21 | async.waterfall([ 22 | function(cb) { log('1.1.1: ', 'start'); cb(null, 3); }, 23 | function(n, cb) { log('1.1.2: ',n); t.inc(n, cb); }, 24 | function(n, cb) { log('1.1.3: ',n); t.fire(n*n, cb); } 25 | ], function (err, result) { 26 | log('1.1 err: ', err); 27 | log('1.1 result: ', result); 28 | }); 29 | //31.749> 1.1.1: start 30 | //31.752> 1.1.2: 3 31 | //31.953> 1.1.3: 4 32 | //32.156> 1.1 err: null 33 | //32.159> 1.1 result: 16 34 | 35 | /** 36 | * 中途有函数出错,其err直接传给最终callback,结果被丢弃,后面的函数不再执行。 37 | */ 38 | // 1.2 39 | async.waterfall([ 40 | function(cb) { log('1.2.1: ', 'start'); cb(null, 3); }, 41 | function(n, cb) { log('1.2.2: ', n); t.inc(n, cb); }, 42 | function(n, cb) { log('1.2.3: ', n); t.err('myerr', cb); }, 43 | function(n, cb) { log('1.2.4: ', n); t.fire(n, cb); } 44 | ], function (err, result) { 45 | log('1.2 err: ', err); 46 | log('1.2 result: ', result); 47 | }); 48 | //44.935> 1.2.1: start 49 | //44.939> 1.2.2: 3 50 | //45.140> 1.2.3: 4 51 | //45.344> 1.2 err: myerr 52 | //45.348> 1.2 result: 53 | 54 | /** 55 | * 注意: 以json形式传入tasks,将不会被执行!! 56 | */ 57 | async.waterfall({ 58 | a: function(cb) { log('1.3.1: ', 'start'); cb(null, 3); }, 59 | b: function(n, cb) { log('1.3.2: ', n); t.inc(n, cb); }, 60 | c: function(n, cb) { log('1.3.3: ', n); t.fire(n*n, cb); } 61 | }, function (err, result) { 62 | log('1.3 err: ', err); 63 | log('1.3 result: ', result); 64 | }); 65 | //49.222> 1.3 err: [Error: First argument to waterfall must be an array of functions] 66 | //49.228> 1.3 result: -------------------------------------------------------------------------------- /whilst_until.js: -------------------------------------------------------------------------------- 1 | var async = require('async'); 2 | var t = require('./t'); 3 | var log = t.log; 4 | 5 | /** 6 | * 相当于while,但其中的异步调用将在完成后才会进行下一次循环。 7 | * 8 | * 它相当于: 9 | * try { 10 | * whilst(test) { 11 | * fn(); 12 | * } 13 | * callback(); 14 | * } catch (err) { 15 | * callback(err); 16 | * } 17 | * 18 | * 该函数的功能比较简单,条件变量通常定义在外面,可供每个函数访问。在循环中,异步调用时产生的值实际上被丢弃了,因为最后那个callback只能传入错误信息。 19 | * 20 | * 另外,第二个函数fn需要能接受一个函数cb,这个cb最终必须被执行,用于表示出错或正常结束。 21 | */ 22 | // whilst(test, fn, callback) 23 | 24 | /** 25 | * 正常情况,没有出错。第二个函数虽然是异步调用,但被同步执行。所以第三个函数被调用时,已经过了3秒。 26 | */ 27 | // 1.1 28 | var count1 = 0; 29 | async.whilst( 30 | function() { return count1 < 3 }, 31 | function(cb) { 32 | log('1.1 count: ', count1); 33 | count1++; 34 | setTimeout(cb, 1000); 35 | }, 36 | function(err) { 37 | // 3s have passed 38 | log('1.1 err: ', err); 39 | } 40 | ); 41 | //10.318> 1.1 count: 0 42 | //11.330> 1.1 count: 1 43 | //12.342> 1.1 count: 2 44 | //13.356> 1.1 err: 45 | 46 | 47 | /** 48 | * 中途出错。出错后立刻调用第三个函数。 49 | */ 50 | // 1.2 51 | var count2 = 0; 52 | async.whilst( 53 | function() { return count2 < 3 }, 54 | function(cb) { 55 | log('1.2 count: ', count2); 56 | if(count2===1) { 57 | t.err('myerr', cb, 200); 58 | } else { 59 | count2++; 60 | setTimeout(cb, 1000); 61 | } 62 | }, 63 | function(err) { 64 | // 2s have passed 65 | log('1.2 err: ', err); 66 | } 67 | ); 68 | //12.805> 1.2 count: 0 69 | //13.824> 1.2 count: 1 70 | //14.026> 1.2 err: myerr 71 | 72 | /** 73 | * 第二个函数即使产生值,也会被忽略。第三个函数只能得到err。 74 | */ 75 | // 1.3 76 | var count3 = 0; 77 | async.whilst( 78 | function() {return count3 < 3 }, 79 | function(cb) { 80 | log('1.3 count: ', count3); 81 | t.inc(count3++, cb); 82 | }, 83 | function(err,result){ // result没有用 84 | log('1.3 err: ', err); 85 | log('1.3 result: ', result); 86 | } 87 | ); 88 | //45.311> 1.3 count: 0 89 | //45.514> 1.3 count: 1 90 | //45.718> 1.3 count: 2 91 | //45.920> 1.3 err: 92 | //45.923> 1.3 result: 93 | 94 | /** 95 | * doWhilst交换了fn,test的参数位置,先执行一次循环,再做test判断。 和javascript中do..while语法一致。 96 | */ 97 | // doWhilst(fn, test, callback) 98 | //1.4 99 | var count4 = 0; 100 | async.doWhilst( 101 | function(cb) { 102 | log('1.4 count: ', count4); 103 | t.inc(count4++, cb); 104 | }, 105 | function() { log("1.4 test"); return count4 < 3 }, 106 | function(err,result){ // result没有用 107 | log('1.4 err: ', err); 108 | log('1.4 result: ', result); 109 | } 110 | ); 111 | //33.643> 1.4 count: 0 112 | //33.848> 1.4 test 113 | //33.850> 1.4 count: 1 114 | //34.054> 1.4 test 115 | //34.057> 1.4 count: 2 116 | //34.269> 1.4 test 117 | //34.270> 1.4 err: 118 | //34.270> 1.4 result: 119 | 120 | /** 121 | * until与whilst正好相反,当test为false时循环,与true时跳出。其它特性一致。 122 | */ 123 | // 1.5 124 | var count5 = 0; 125 | async.until( 126 | function() { return count5>3 }, 127 | function(cb) { 128 | log('1.5 count: ', count5); 129 | count5++; 130 | setTimeout(cb, 200); 131 | }, 132 | function(err) { 133 | // 4s have passed 134 | log('1.5 err: ',err); 135 | } 136 | ); 137 | //42.498> 1.5 count: 0 138 | //42.701> 1.5 count: 1 139 | //42.905> 1.5 count: 2 140 | //43.107> 1.5 count: 3 141 | //43.313> 1.5 err: 142 | 143 | /** 144 | * doUntil与doWhilst正好相反,当test为false时循环,与true时跳出。其它特性一致。 145 | */ 146 | // doUntil(fn, test, callback) 147 | // 1.6 148 | var count6 = 0; 149 | async.doUntil( 150 | function(cb) { 151 | log('1.6 count: ', count6); 152 | count6++; 153 | setTimeout(cb, 200); 154 | }, 155 | function() { log('1.6 test');return count6>3 }, 156 | function(err) { 157 | // 4s have passed 158 | log('1.6 err: ',err); 159 | } 160 | ); 161 | //41.831> 1.6 count: 0 162 | //42.035> 1.6 test 163 | //42.037> 1.6 count: 1 164 | //42.241> 1.6 test 165 | //42.244> 1.6 count: 2 166 | //42.456> 1.6 test 167 | //42.457> 1.6 count: 3 168 | //42.660> 1.6 test 169 | //42.661> 1.6 err: 170 | 171 | /** 172 | * forever,无论条件循环执行,如果不出错,callback永远不被执行 173 | */ 174 | //forever(fn, callback) 175 | //1.7 176 | var count7 = 0; 177 | async.forever( 178 | function(cb) { 179 | log('1.7 count: ', count7); 180 | count7++; 181 | setTimeout(cb, 200); 182 | }, 183 | function(err) { 184 | log('1.7 err: ',err); 185 | } 186 | ); 187 | //52.770> 1.7 count: 0 188 | //52.973> 1.7 count: 1 189 | //53.175> 1.7 count: 2 190 | //53.377> 1.7 count: 3 191 | //53.583> 1.7 count: 4 192 | //53.785> 1.7 count: 5 193 | //53.987> 1.7 count: 6 194 | //54.189> 1.7 count: 7 195 | //54.391> 1.7 count: 8 196 | //54.593> 1.7 count: 9 197 | //54.795> 1.7 count: 10 198 | //54.997> 1.7 count: 11 199 | //55.199> 1.7 count: 12 --------------------------------------------------------------------------------