zoukankan      html  css  js  c++  java
  • (一)Nodejs

    简介

    Async是一个流程控制工具包,提供了直接而强大的异步功能

    应用场景

    业务流程逻辑复杂,适应异步编程,减少回调的嵌套

    安装

    npm insatll async

    函数介绍

    • Collections

    each: 如果想对同一个集合中的所有元素都执行同一个异步操作。 

      1 var async = require('async');
      2 
      3 var t = require('./t');
      4 var log = t.log;
      5 
      6 /**
      7  * 
      8  * async提供了三种方式:
      9  * 1. 集合中所有元素并行执行
     10  * 2. 一个一个顺序执行
     11  * 3. 分批执行,同一批内并行,批与批之间按顺序
     12  *
     13  * 如果中途出错,则错误将上传给最终的callback处理。其它已经启动的任务继续执行,未启动的忽略。
     14  */
     15 // each(arr, iterator(item, callback), callback(err))
     16 
     17 
     18 var arr = [{name:'Jack', delay: 200},
     19            {name:'Mike', delay: 100},
     20            {name:'Freewind', delay: 300}];
     21 
     22 /**
     23  * 所有操作并发执行,且全部未出错,最终得到的err为undefined。注意最终callback只有一个参数err。
     24  */
     25 // 1.1
     26 async.each(arr, function(item, callback) {
     27     log('1.1 enter: ' + item.name);
     28     setTimeout(function(){
     29         log('1.1 handle: ' + item.name);
     30         callback(null, item.name);
     31     }, item.delay);
     32 }, function(err) {
     33     log('1.1 err: ' + err);
     34 });
     35 // 输出如下:
     36 // 42.244> 1.1 enter: Jack
     37 // 42.245> 1.1 enter: Mike
     38 // 42.245> 1.1 enter: Freewind
     39 // 42.350> 1.1 handle: Mike
     40 // 42.445> 1.1 handle: Jack
     41 // 42.554> 1.1 handle: Freewind
     42 // 42.554> 1.1 err: undefined
     43 
     44 
     45 /**
     46  * 如果中途出错,则出错后马上调用最终的callback。其它未执行完的任务继续执行。
     47  */
     48 async.each(arr,function(item, callback) {
     49     log('1.2 enter: ' +item.name);
     50     setTimeout(function() {
     51         log('1.2 handle: ' + item.name);
     52         if(item.name==='Jack') {
     53             callback('myerr');
     54         }
     55     }, item.delay);
     56 }, function(err) {
     57     log('1.2 err: ' + err);
     58 });
     59 // 输出如下:
     60 // 42.246> 1.2 enter: Jack
     61 // 42.246> 1.2 enter: Mike
     62 // 42.246> 1.2 enter: Freewind
     63 // 42.350> 1.2 handle: Mike
     64 // 42.445> 1.2 handle: Jack
     65 // 42.446> 1.2 err: myerr
     66 // 42.555> 1.2 handle: Freewind
     67 
     68 /**
     69  * 与each相似,但不是并行执行。而是一个个按顺序执行。
     70  */
     71 async.eachSeries(arr, function(item, callback) {
     72     log('1.3 enter: ' + item.name);
     73     setTimeout(function(){
     74         log('1.3 handle: ' + item.name);
     75         callback(null, item.name);
     76     }, item.delay);
     77 }, function(err) {
     78     log('1.3 err: ' + err);
     79 });
     80 // 42.247> 1.3 enter: Jack
     81 // 42.459> 1.3 handle: Jack
     82 // 42.459> 1.3 enter: Mike
     83 // 42.569> 1.3 handle: Mike
     84 // 42.569> 1.3 enter: Freewind
     85 // 42.883> 1.3 handle: Freewind
     86 // 42.883> 1.3 err: undefined
     87 
     88 /**
     89  * 如果中途出错,则马上把错误传给最终的callback,还未执行的不再执行。
     90  */
     91 async.eachSeries(arr,function(item, callback) {
     92     log('1.4 enter: ' +item.name);
     93     setTimeout(function() {
     94         log('1.4 handle: ' + item.name);
     95         if(item.name==='Jack') {
     96             callback('myerr');
     97         }
     98     }, item.delay);
     99 }, function(err) {
    100     log('1.4 err: ' + err);
    101 });
    102 // 42.247> 1.4 enter: Jack
    103 // 42.460> 1.4 handle: Jack
    104 // 42.460> 1.4 err: myerr
    105 
    106 /**
    107  * 分批执行,第二个参数是每一批的个数。每一批内并行执行,但批与批之间按顺序执行。
    108  */
    109 async.eachLimit(arr, 2, function(item, callback) {
    110     log('1.5 enter: ' + item.name);
    111     setTimeout(function(){
    112         log('1.5 handle: ' + item.name);
    113         callback(null, item.name);
    114     }, item.delay);
    115 }, function(err) {
    116     log('1.5 err: ' + err);
    117 });
    118 // 42.247> 1.5 enter: Jack
    119 // 42.248> 1.5 enter: Mike
    120 // 42.351> 1.5 handle: Mike
    121 // 42.352> 1.5 enter: Freewind
    122 // 42.461> 1.5 handle: Jack
    123 // 42.664> 1.5 handle: Freewind
    124 // 42.664> 1.5 err: undefined
    125 
    126 /**
    127  * 如果中途出错,错误将马上传给最终的callback。同一批中的未执行完的任务还将继续执行,但下一批及以后的不再执行。
    128  */
    129 async.eachLimit(arr,2,function(item, callback) {
    130     log('1.6 enter: ' +item.name);
    131     setTimeout(function() {
    132         log('1.6 handle: ' + item.name);
    133         if(item.name==='Jack') {
    134             callback('myerr');
    135         }
    136     }, item.delay);
    137 }, function(err) {
    138     log('1.6 err: ' + err);
    139 });
    140 // 42.248> 1.6 enter: Jack
    141 // 42.248> 1.6 enter: Mike
    142 // 42.352> 1.6 handle: Mike
    143 // 42.462> 1.6 handle: Jack
    144 // 42.462> 1.6 err: myerr
    View Code

    map: 对集合中的每一个元素,执行某个异步操作,得到结果。所有的结果将汇总到最终的callback里。与each的区别是,each只关心操作不管最后的值,而map关心的最后产生的值。

      1 var async = require('async');
      2 
      3 var t = require('./t');
      4 var log = t.log;
      5 
      6 /**
      7  
      8  * 提供了两种方式:
      9  * 1. 并行执行。同时对集合中所有元素进行操作,结果汇总到最终callback里。如果出错,则立刻返回错误以及已经执行完的任务的结果,未执行完的占个空位
     10  * 2. 顺序执行。对集合中的元素一个一个执行操作,结果汇总到最终callback里。如果出错,则立刻返回错误以及已经执行完的结果,未执行的被忽略。
     11  */
     12 // map(arr, iterator(item, callback), callback(err, results))
     13 
     14 var arr = [{name:'Jack', delay:200}, {name:'Mike', delay: 100}, {name:'Freewind', delay:300}, {name:'Test', delay: 50}];
     15 
     16 /**
     17  * 所有操作均正确执行,未出错。所有结果按元素顺序汇总给最终的callback。
     18  */
     19 // 1.1
     20 async.map(arr, function(item, callback) {
     21     log('1.1 enter: ' + item.name);
     22     setTimeout(function() {
     23         log('1.1 handle: ' + item.name);
     24         callback(null, item.name + '!!!');
     25     }, item.delay);
     26 }, function(err,results) {
     27     log('1.1 err: ', err);
     28     log('1.1 results: ', results);
     29 });
     30 // 54.569> 1.1 enter: Jack
     31 // 54.569> 1.1 enter: Mike
     32 // 54.569> 1.1 enter: Freewind
     33 // 54.569> 1.1 enter: Test
     34 // 54.629> 1.1 handle: Test
     35 // 54.679> 1.1 handle: Mike
     36 // 54.789> 1.1 handle: Jack
     37 // 54.879> 1.1 handle: Freewind
     38 // 54.879> 1.1 err:
     39 // 54.879> 1.1 results: [ 'Jack!!!', 'Mike!!!', 'Freewind!!!', 'Test!!!' ]
     40 
     41 /**
     42 *  如果中途出错,立刻将错误、以及已经执行完成的结果汇总给最终callback。未执行完的将会在结果数组中用占个空位。
     43 */
     44 async.map(arr, function(item, callback) {
     45     log('1.2 enter: ' + item.name);
     46     setTimeout(function() {
     47         log('1.2 handle: ' + item.name);
     48         if(item.name==='Jack') callback('myerr');
     49         else callback(null, item.name+'!!!');
     50     }, item.delay);
     51 }, function(err, results) {
     52     log('1.2 err: ', err);
     53     log('1.2 results: ', results);
     54 });
     55 // 54.569> 1.2 enter: Jack
     56 // 54.569> 1.2 enter: Mike
     57 // 54.569> 1.2 enter: Freewind
     58 // 54.569> 1.2 enter: Test
     59 // 54.629> 1.2 handle: Test
     60 // 54.679> 1.2 handle: Mike
     61 // 54.789> 1.2 handle: Jack
     62 // 54.789> 1.2 err: myerr
     63 // 54.789> 1.2 results: [ undefined, 'Mike!!!', , 'Test!!!' ]
     64 // 54.879> 1.2 handle: Freewind
     65 
     66 /**
     67 * 顺序执行,一个完了才执行下一个。
     68 */
     69 async.mapSeries(arr, function(item, callback) {
     70     log('1.3 enter: ' + item.name);
     71     setTimeout(function() {
     72         log('1.3 handle: ' + item.name);
     73         callback(null, item.name+'!!!');
     74     }, item.delay);
     75 }, function(err,results) {
     76     log('1.3 err: ', err);
     77     log('1.3 results: ', results);
     78 });
     79 // 54.569> 1.3 enter: Jack
     80 // 54.789> 1.3 handle: Jack
     81 // 54.789> 1.3 enter: Mike
     82 // 54.899> 1.3 handle: Mike
     83 // 54.899> 1.3 enter: Freewind
     84 // 55.209> 1.3 handle: Freewind
     85 // 55.209> 1.3 enter: Test
     86 // 55.269> 1.3 handle: Test
     87 // 55.269> 1.3 err:
     88 // 55.269> 1.3 results: [ 'Jack!!!', 'Mike!!!', 'Freewind!!!', 'Test!!!' ]
     89 
     90 /**
     91 * 顺序执行过程中出错,只把错误以及执行完的传给最终callback,未执行的忽略。
     92 */
     93 async.mapSeries(arr, function(item, callback) {
     94     log('1.4 enter: ' + item.name);
     95     setTimeout(function() {
     96         log('1.4 handle: ' + item.name);
     97         if(item.name==='Mike') callback('myerr');
     98         else callback(null, item.name+'!!!');
     99     }, item.delay);
    100 }, function(err, results) {
    101     log('1.4 err: ', err);
    102     log('1.4 results: ', results);
    103 });
    104 // 47.616> 1.4 enter: Jack
    105 // 47.821> 1.4 handle: Jack
    106 // 47.821> 1.4 enter: Mike
    107 // 47.931> 1.4 handle: Mike
    108 // 47.931> 1.4 err: myerr
    109 // 47.932> 1.4 results: [ 'Jack!!!', undefined ]
    110 
    111 /**
    112  * 并行执行,同时最多2个函数并行,传给最终callback。
    113  */
    114 //1.5
    115 async.mapLimit(arr,2, function(item, callback) {
    116     log('1.5 enter: ' + item.name);
    117     setTimeout(function() {
    118         log('1.5 handle: ' + item.name);
    119         if(item.name==='Jack') callback('myerr');
    120         else callback(null, item.name+'!!!');
    121     }, item.delay);
    122 }, function(err, results) {
    123     log('1.5 err: ', err);
    124     log('1.5 results: ', results);
    125 });
    126 //57.797> 1.5 enter: Jack
    127 //57.800> 1.5 enter: Mike
    128 //57.900> 1.5 handle: Mike
    129 //57.900> 1.5 enter: Freewind
    130 //58.008> 1.5 handle: Jack
    131 //58.009> 1.5 err: myerr
    132 //58.009> 1.5 results: [ undefined, 'Mike!!!' ]
    133 //58.208> 1.5 handle: Freewind
    134 //58.208> 1.5 enter: Test
    135 //58.273> 1.5 handle: Test
    View Code

    filter: 使用异步操作对集合中的元素进行筛选, 需要注意的是,iterator的callback只有一个参数,只能接收true或false。
    reject: reject跟filter正好相反,当测试为true时则抛弃

      1 var async = require('async');
      2 
      3 var t = require('./t');
      4 var log = t.log;
      5 
      6 /**
      7  * 对于出错,该函数没有做出任何处理,直接由nodejs抛出。所以需要注意对Error的处理。
      8  *
      9  * async提供了两种方式:
     10  * 1. 并行执行:filter
     11  * 2. 顺序执行:filterSereis
     12  */
     13 // filter(arr, iterator(item, callback(test)), callback(results))
     14 
     15 var arr = [1,2,3,4,5];
     16 
     17 /**
     18  * 并行执行,对arr进行筛选。
     19  */
     20 async.filter(arr, function(item, callback) {
     21     log('1.1 enter: ' + item);
     22     setTimeout(function() {
     23         log('1.1 test: ' + item);
     24         callback(item>=3);
     25     }, 200);
     26 }, function(results) {
     27     log('1.1 results: ', results);
     28 });
     29 //16.739> 1.1 enter: 1
     30 //16.749> 1.1 enter: 2
     31 //16.749> 1.1 enter: 3
     32 //16.749> 1.1 enter: 4
     33 //16.749> 1.1 enter: 5
     34 //16.749> 1.3 enter: 1
     35 //16.949> 1.1 test: 1
     36 //16.949> 1.1 test: 2
     37 //16.949> 1.1 test: 3
     38 //16.949> 1.1 test: 4
     39 //16.949> 1.1 test: 5
     40 //16.949> 1.1 results: [ 3, 4, 5 ]
     41 
     42 
     43 /**
     44 * 串行执行,对arr进行筛选。
     45 */
     46 // 1.3
     47 async.filterSeries(arr, function(item, callback) {
     48     log('1.3 enter: ' + item);
     49     setTimeout(function() {
     50         log('1.3 handle: ' + item);
     51         callback(item>=3);
     52     }, 200);
     53 }, function(results) {
     54     log('1.3 results: ', results);
     55 });
     56 // 16.749> 1.3 enter: 1
     57 // 16.949> 1.3 handle: 1
     58 // 16.949> 1.3 enter: 2
     59 // 17.149> 1.3 handle: 2
     60 // 17.149> 1.3 enter: 3
     61 // 17.369> 1.3 handle: 3
     62 // 17.369> 1.3 enter: 4
     63 // 17.589> 1.3 handle: 4
     64 // 17.589> 1.3 enter: 5
     65 // 17.789> 1.3 handle: 5
     66 // 17.789> 1.3 results: [ 3, 4, 5 ]
     67 
     68 
     69 /*
     70 * 并行reject
     71 */
     72 // reject(arr, iterator(item, callback(test)), callback(results)
     73 async.reject(arr, function(item, callback) {
     74     log('1.4 enter: ' + item);
     75     setTimeout(function() {
     76         log('1.4 test: ' + item);
     77         callback(item>=3);
     78     }, 200);
     79 }, function(results) {
     80     log('1.4 results: ', results);
     81 });
     82 // 31.359> 1.4 enter: 1
     83 // 31.359> 1.4 enter: 2
     84 // 31.359> 1.4 enter: 3
     85 // 31.359> 1.4 enter: 4
     86 // 31.359> 1.4 enter: 5
     87 // 31.559> 1.4 test: 1
     88 // 31.559> 1.4 test: 2
     89 // 31.559> 1.4 test: 3
     90 // 31.559> 1.4 test: 4
     91 // 31.559> 1.4 test: 5
     92 // 31.569> 1.4 results: [ 1, 2 ]
     93 
     94 
     95 /**
     96  * 串行执行,对arr进行筛选。
     97  */
     98 // 1.3
     99 async.rejectSeries(arr, function(item, callback) {
    100     log('1.5 enter: ' + item);
    101     setTimeout(function() {
    102         log('1.5 handle: ' + item);
    103         callback(item>=3);
    104     }, 200);
    105 }, function(results) {
    106     log('1.5 results: ', results);
    107 });
    108 //43.592> 1.5 enter: 1
    109 //43.799> 1.5 handle: 1
    110 //43.800> 1.5 enter: 2
    111 //44.004> 1.5 handle: 2
    112 //44.007> 1.5 enter: 3
    113 //44.210> 1.5 handle: 3
    114 //44.211> 1.5 enter: 4
    115 //44.412> 1.5 handle: 4
    116 //44.413> 1.5 enter: 5
    117 //44.614> 1.5 handle: 5
    118 //44.616> 1.5 results: [ 1, 2 ]
    View Code

    reduce: 可以让我们给定一个初始值,用它与集合中的每一个元素做运算,最后得到一个值。reduce从左向右来遍历元素,如果想从右向左,可使用reduceRight。

     1 var async = require('async');
     2 
     3 var t = require('./t');
     4 var log = t.log;
     5 
     6 
     7 //reduce(arr, memo, iterator(memo,item,callback), callback(err,result))
     8 //alias: inject, foldl
     9 
    10 var arr = [1,3,5];
    11 
    12 /**
    13  * 顺序执行
    14  */
    15 async.reduce(arr, 100, function(memo, item, callback) {
    16     log('1.1 enter: ' + memo +', ' + item);
    17     setTimeout(function() {
    18         callback(null, memo+item);
    19     }, 100);
    20 },function(err, result) {
    21     log('1.1 err: ', err);
    22     log('1.1 result: ', result);
    23 });
    24 // 28.789> 1.1 enter: 100, 1
    25 // 28.889> 1.1 enter: 101, 3
    26 // 28.999> 1.1 enter: 104, 5
    27 // 29.109> 1.1 err:
    28 // 29.109> 1.1 result: 109
    29 
    30 /**
    31  * 顺序执行过程中出错,只把错误传给最终callback,结果是null
    32  */
    33 async.reduce(arr, 100, function(memo, item, callback) {
    34     log('1.2 enter: ' + memo +', ' + item);
    35     setTimeout(function() {
    36         if(item===3) callback('myerr');
    37         else callback(null, memo+item);
    38     }, 100);
    39 },function(err, result) {
    40     log('1.2 err: ', err);
    41     log('1.2 result: ', result);
    42 });
    43 // 05.541> 1.2 enter: 100, 1
    44 // 05.649> 1.2 enter: 101, 3
    45 // 05.760> 1.2 err: myerr
    46 // 05.760> 1.2 result:
    47 
    48 /**
    49  * 顺序执行从右向左
    50  *
    51  * alias: foldr
    52  */
    53 async.reduceRight(arr, 100, function(memo, item, callback) {
    54     log('1.3 enter: ' + memo +', ' + item);
    55     setTimeout(function() {
    56         callback(null, memo+item);
    57     }, 100);
    58 },function(err, result) {
    59     log('1.3 err: ', err);
    60     log('1.3 result: ', result);
    61 });
    62 // 28.789> 1.3 enter: 100, 5
    63 // 28.889> 1.3 enter: 105, 3
    64 // 28.999> 1.3 enter: 108, 1
    65 // 29.109> 1.3 err:
    66 // 29.109> 1.3 result: 109
    View Code

    detect: 用于取得集合中满足条件的第一个元素。

     1 var async = require('async');
     2 
     3 var t = require('./t');
     4 var log = t.log;
     5 
     6 // detect(array, iterator(item,callback(test)), callback(result)
     7 
     8 var arr = [
     9     {value:1,delay:500},
    10     {value:2,delay:200},
    11     {value:3,delay:300}
    12 ];
    13 
    14 /**
    15  *  并行执行,通过t.inc做一个累加器,得到第一个满足条件的结果对象
    16  */
    17 async.detect(arr, function(item,callback){
    18     log('1.1 enter: ', item.value);
    19     t.inc(item.value, function(err,n) {
    20         log('1.1 handle: ', item.value);
    21         callback(n%2===0);
    22     }, item.delay);
    23 }, function(result) {
    24     log('1.1 result: ', result);
    25 });
    26 // 09.928> 1.1 enter: 1
    27 // 09.928> 1.1 enter: 2
    28 // 09.928> 1.1 enter: 3
    29 // 10.138> 1.1 handle: 2
    30 // 10.228> 1.1 handle: 3
    31 // 10.228> 1.1 result: { value: 3, delay: 300 }
    32 // 10.438> 1.1 handle: 1
    33 // 10.438> 1.1 handle: 1
    34 
    35 /**
    36  *  串行执行,通过t.inc做一个累加器,得到第一个满足条件的结果对象
    37  */
    38 async.detectSeries(arr, function(item,callback) {
    39     log('1.2 enter: ', item.value);
    40     t.inc(item.value, function(err,n) {
    41         log('1.1 handle: ', item.value);
    42         callback(n%2===0);
    43     }, item.delay);
    44 }, function(result) {
    45     log('1.2 result: ', result);
    46 });
    47 // 09.928> 1.2 enter: 1
    48 // 10.438> 1.2 result: { value: 1, delay: 500 }
    View Code

    sortBy: 对集合内的元素进行排序,依据每个元素进行某异步操作后产生的值,从小到大排序。

     1 var async = require('async');
     2 
     3 var t = require('./t');
     4 var log = t.log;
     5 
     6 // sortBy(array, iterator(item,callback(err,result)), callback(err,results))
     7 
     8 var arr = [3,6,1];
     9 
    10 /**
    11  * 通过异步迭代器,对集合进行排序
    12  */
    13 async.sortBy(arr, function(item, callback) {
    14     setTimeout(function() {
    15         callback(null,item);
    16     }, 200);
    17 }, function(err,results) {
    18     log('1.1 err: ', err);
    19     log('1.1 results: ', results);
    20 });
    21 // 26.562> 1.1 err: null
    22 // 26.562> 1.1 results: [ 1, 3, 6 ]
    23 
    24 /**
    25  * 迭代出错,callback返回err,没有results
    26  */
    27 async.sortBy(arr, function(item, callback) {
    28     setTimeout(function() {
    29         if(item===6) callback('myerr');
    30         else callback(null,item);
    31     }, 200);
    32 }, function(err,results) {
    33     log('1.2 err: ', err);
    34     log('1.2 results: ', results);
    35 });
    36 // 26.572> 1.2 err: myerr
    37 // 26.572> 1.2 results:
    View Code

    some: 当集合中是否有至少一个元素满足条件时,即最终callback得到的值为true,否则为false.

     1 var async = require('async');
     2 
     3 var t = require('./t');
     4 var log = t.log;
     5 
     6 // some(arr, iterator(item,callback(test)), callback(result))
     7 //alias: any
     8 
     9 var arr = [1,2,3,6];
    10 
    11 /**
    12  * 串行执行,集合中至少有一个元素<=3,所以结果为true
    13  */
    14 // 1.1
    15 async.some(arr, function(item,callback){
    16     log('1.1 enter: ',item);
    17     setTimeout(function(){
    18         log('1.1 handle: ',item);
    19         callback(item<=3);
    20     },100);
    21 }, function(result) {
    22     log('1.1 result: ', result);
    23 });
    24 // 36.165> 1.1 enter: 1
    25 // 36.165> 1.1 enter: 2
    26 // 36.165> 1.1 enter: 3
    27 // 36.165> 1.1 enter: 6
    28 // 36.275> 1.1 handle: 1
    29 // 36.275> 1.1 result: true
    30 // 36.275> 1.1 handle: 2
    31 // 36.275> 1.1 handle: 3
    32 // 36.275> 1.1 handle: 6
    33 
    34 
    35 /**
    36  * 串行执行,集合中没有一个元素>10,所以结果为false
    37  */
    38 async.some(arr, function(item,callback){
    39     log('1.2 enter: ',item);
    40     setTimeout(function(){
    41         log('1.2 handle: ',item);
    42         callback(item>10);
    43     },100);    
    44 }, function(result) {
    45     log('1.2 result: ', result);
    46 });
    47 // 36.165> 1.2 enter: 1
    48 // 36.165> 1.2 enter: 2
    49 // 36.165> 1.2 enter: 3
    50 // 36.165> 1.2 enter: 6
    51 // 36.275> 1.2 handle: 1
    52 // 36.275> 1.2 handle: 2
    53 // 36.275> 1.2 handle: 3
    54 // 36.275> 1.2 handle: 6
    55 // 36.275> 1.2 result: false
    View Code

    every: 如果集合里每一个元素都满足条件,则传给最终回调的result为true,否则为false

     1 var async = require('async');
     2 
     3 var t = require('./t');
     4 var log = t.log;
     5  
     6 // every(arr, iterator(item,callback), callback(result))
     7 //alias: all
     8 
     9 var arr = [1,2,3,6];
    10 
    11 /**
    12  * 串行执行,集合中所有的元素都<=10,所以为true
    13  */
    14 async.every(arr, function(item,callback){
    15     log('1.1 enter: ',item);
    16     setTimeout(function(){
    17         log('1.1 handle: ',item);
    18         callback(item<=10);
    19     },100);    
    20 }, function(result) {
    21     log('1.1 result: ', result);
    22 });
    23 // 32.113> 1.1 enter: 1
    24 // 32.123> 1.1 enter: 2
    25 // 32.123> 1.1 enter: 3
    26 // 32.123> 1.1 enter: 6
    27 // 32.233> 1.1 handle: 1
    28 // 32.233> 1.1 handle: 2
    29 // 32.233> 1.1 handle: 3
    30 // 32.233> 1.1 handle: 6
    31 // 32.233> 1.1 result: true
    32 
    33 /**
    34  * 串行执行,集合中至少有一个元素不大于2,所以为false
    35  */
    36 async.every(arr, function(item,callback){
    37     log('1.2 enter: ',item);
    38     setTimeout(function(){
    39         log('1.2 handle: ',item);
    40         callback(item>2);
    41     },100);    
    42 }, function(result) {
    43     log('1.2 result: ', result);
    44 });
    45 // 32.123> 1.2 enter: 1
    46 // 32.123> 1.2 enter: 2
    47 // 32.123> 1.2 enter: 3
    48 // 32.123> 1.2 enter: 6
    49 // 32.233> 1.2 handle: 1
    50 // 32.233> 1.2 result: false
    51 // 32.233> 1.2 handle: 2
    52 // 32.233> 1.2 handle: 3
    53 // 32.233> 1.2 handle: 6
    View Code

    concat: 将多个异步操作的结果合并为一个数组。

     1 var async = require('async');
     2 
     3 var t = require('./t');
     4 var log = t.log;
     5 
     6 // concat(arr, iterator(item,callback(err,result)), callback(err,result))
     7 
     8 var data = {
     9     aaa: [11,22,33],
    10     bbb: [44,55],
    11     ccc: 66
    12 };
    13 
    14 var keys = [
    15     {name: 'aaa', delay: 300},
    16     {name: 'bbb', delay: 100},
    17     {name: 'ccc', delay: 200}
    18 ];
    19 
    20 /**
    21  * 以并行方式对集合中各元素进行异步操作,然后把得到的结果合并为一个数组,传给最后的callback。
    22  */
    23 // 1.1
    24 async.concat(keys, function(key,callback) {
    25     setTimeout(function() {
    26         callback(null, data[key.name]);
    27     }, key.delay);
    28 }, function(err, values) {
    29     log('1.1 err: ', err);
    30     log('1.1 values: ', values);    
    31 });
    32 // 13.539> 1.1 err:
    33 // 13.539> 1.1 values: [ 44, 55, 66, 11, 22, 33 ]
    34 
    35 /**
    36  * 如果中途出错,则把错误以及已经完成的操作的结果交给最后callback。未执行完的则忽略。
    37  */
    38 // 1.2
    39 async.concat(keys, function(key,callback) {
    40     setTimeout(function() {
    41         if(key.name==='ccc') callback('myerr');
    42         else callback(null, data[key.name]);
    43     }, key.delay);
    44 }, function(err, values) {
    45     log('1.2 err: ', err);
    46     log('1.2 values: ', values);    
    47 });
    48 // 13.439> 1.2 err: myerr
    49 // 13.439> 1.2 values: [ 44, 55 ]
    50 
    51 /**
    52  * 按数组中的元素顺序来执行异步操作,一个完成后才对下一个进行操作。所有结果会汇集成一个数组交给最后的callback。
    53  */
    54 // concatSeries(arr, iterator, callback)
    55 
    56 // 1.3
    57 async.concatSeries(keys, function(key,callback) {
    58     setTimeout(function() {
    59         callback(null, data[key.name]);
    60     }, key.delay);
    61 }, function(err, values) {
    62     log('1.3 err: ', err);
    63     log('1.3 values: ', values);    
    64 });
    65 // 13.859> 1.3 err:
    66 // 13.859> 1.3 values: [ 11, 22, 33, 44, 55, 66 ]
    View Code
    • ControlFlow

    series: 串行执行,一个函数数组中的每个函数,每一个函数执行完成之后才能执行下一个函数。

     1 var async = require('async');
     2 
     3 var t = require('./t');
     4 var log = t.log;
     5 
     6 /**
     7  * 如果任何一个函数向它的回调函数中传了一个error,则后面的函数都不会被执行,并且会立刻将该error以及已经执行了的函数的结果,传给series中最后那个callback。
     8  * 当所有的函数执行完后(没有出错),则会把每个函数传给其回调函数的结果合并为一个数组,传给series最后的那个callback。
     9  * 还可以json的形式来提供tasks。每一个属性都会被当作函数来执行,并且结果也会以json形式传给series最后的那个callback。这种方式可读性更高一些。
    10  */
    11 // series(tasks, [callback])
    12 
    13 /**
    14  * 全部函数都正常执行。每个函数产生的值将按顺序合并为一个数组,传给最终的callback。
    15  */
    16 // 1.1
    17 async.series([
    18     function(cb) { t.inc(3, cb); },
    19     function(cb) { t.inc(8, cb); },
    20     function(cb) { t.inc(2, cb); }
    21 ], function(err, results) {
    22     log('1.1 err: ', err);
    23     log('1.1 results: ', results);
    24 });
    25 //05.155> 1.1 err: null
    26 //05.156> 1.1 results: [ 4, 9, 3 ]
    27 
    28 /**
    29  * 中间有函数出错。出错之后的函数不会执行,错误及之前正常执行的函数结果将传给最终的callback。
    30  */
    31 // 1.2
    32 async.series([
    33     function(cb) { t.inc(3, cb); },
    34     function(cb) { t.err('test_err', cb); },
    35     function(cb) { t.inc(8, cb); }
    36 ], function (err, results) {
    37     log('1.2 err: ', err);
    38     log('1.2 results: ', results);
    39 });
    40 //04.964> 1.2 err: test_err
    41 //04.973> 1.2 results: [ 4, undefined ]
    42 
    43 /**
    44  * 如果某个函数传的数据是undefined, null, {}, []等,它们会原样传给最终callback。
    45  */
    46 // 1.3
    47 async.series([
    48     function(cb) { t.fire(3, cb);},
    49     function(cb) { t.fire(undefined, cb); },
    50     function(cb) { t.fire(null, cb); },
    51     function(cb) { t.fire({}, cb); },
    52     function(cb) { t.fire([], cb); },
    53     function(cb) { t.fire('abc', cb) }
    54 ], function(err, results) {
    55     log('1.3 err: ', err);
    56     log('1.3 results: ', results);
    57 });
    58 //05.794> 1.3 err: null
    59 //05.795> 1.3 results: [ 3, undefined, null, {}, [], 'abc' ]
    60 
    61 /**
    62  * 以json形式传入tasks。其结果也将以json形式传给最终callback。
    63  */
    64 async.series({
    65     a: function(cb) { t.inc(3, cb); },
    66     b: function(cb) { t.fire(undefined, cb); },
    67     c: function (cb) { t.err('myerr', cb); },
    68     d: function (cb) { t.inc(8, cb); }
    69 }, function (err, results) {
    70     log('1.4 err: ', err);
    71     log('1.4 results: ', results);
    72 });
    73 //05.178> 1.4 err: myerr
    74 //05.179> 1.4 results: { a: 4, b: undefined, c: undefined }
    View Code

    parallel: 并行执行多个函数,每个函数都是立即执行,不需要等待其它函数先执行。传给最终callback的数组中的数据按照tasks中声明的顺序,而不是执行完成的顺序。

     1 var async = require('async');
     2 var t = require('./t');
     3 var log = t.log;
     4 
     5 /**
     6  * 如果某个函数出错,则立刻将err和已经执行完的函数的结果值传给parallel最终的callback。其它未执行完的函数的值不会传到最终数据,但要占个位置。
     7  * 同时支持json形式的tasks,其最终callback的结果也为json形式。
     8  */
     9 // parallel(tasks, [callback])
    10 
    11 /**
    12  * 并行执行多个函数,每个函数的值将按函数声明的先后顺序汇成一个数组,传给最终callback。
    13  */
    14 // 1.1
    15 async.parallel([
    16     function(cb) { t.fire('a400', cb, 400) },
    17     function(cb) { t.fire('a200', cb, 200) },
    18     function(cb) { t.fire('a300', cb, 300) }
    19 ], function (err, results) {
    20     log('1.1 err: ', err);
    21     log('1.1 results: ', results);
    22 });
    23 //36.929> 1.1 err: null
    24 //36.930> 1.1 results: [ 'a400', 'a200', 'a300' ]
    25 
    26 /**
    27 * 如果中途有个函数出错,则将该err和已经完成的函数值汇成一个数组,传给最终的callback。还没有执行完的函数的值将被忽略,但要在最终数组中占个位置
    28 */
    29 // 1.2
    30 async.parallel([
    31     function(cb) { log('1.2.1: ', 'start'); t.fire('a400', cb, 400) }, // 该函数的值不会传给最终callback,但要占个位置
    32     function(cb) { log('1.2.2: ', 'start'); t.err('e200', cb, 200) },
    33     function(cb) { log('1.2.3: ', 'start'); t.fire('a100', cb, 100) }
    34 ], function(err, results) {
    35     log('1.2 err: ', err);
    36     log('1.2 results: ', results);
    37 });
    38 //36.537> 1.2.1: start
    39 //36.540> 1.2.2: start
    40 //36.541> 1.2.3: start
    41 //36.741> 1.2 err: e200
    42 //36.744> 1.2 results: [ , undefined, 'a100' ]
    43 
    44 /**
    45 * 以json形式传入tasks,最终results也为json
    46 */
    47 // 1.3
    48 async.parallel({
    49     a: function(cb) { t.fire('a400', cb, 400) },
    50     b: function(cb) { t.fire('c300', cb, 300) }
    51 }, function(err, results) {
    52     log('1.3 err: ', err);
    53     log('1.3 results: ', results);
    54 });
    55 //36.943> 1.3 err: null
    56 //36.944> 1.3 results: { b: 'c300', a: 'a400' }
    57 
    58 /**
    59 * 如果中途出错,会将err与已经完成的函数值(汇成一个json)传给最终callback。未执行完成的函数值被忽略,不会出现在最终json中。
    60 */
    61 // 1.4
    62 async.parallel({
    63     a: function(cb) { t.fire('a400', cb, 400) }, // 该函数的值不会传给最终的callback
    64     b: function(cb) { t.err('e300', cb, 300) },
    65     c: function(cb) { t.fire('c200', cb, 200) }
    66 }, function(err, results) {
    67     log('1.4 err: ', err);
    68     log('1.4 results: ', results);
    69 });
    70 //36.853> 1.4 err: e300
    71 //36.854> 1.4 results: { c: 'c200', b: undefined }
    72 
    73 /**
    74  * 并行执行,同时最多2个函数并行,传给最终callback。
    75  */
    76 //1.5
    77 async.parallelLimit({
    78     a:function(cb) { log('a start'); t.fire('a400', cb, 200) },
    79     b:function(cb) { log('b start'); t.fire('b200', cb, 200) },
    80     c:function(cb) { log('c start'); t.fire('c100', cb, 100) },
    81     d:function(cb) { log('d start'); t.fire('d600', cb, 600) },
    82     e:function(cb) { log('e start'); t.fire('e300', cb, 300) }
    83 },2, function(err, results) {
    84     log('1.5 err: ', err);
    85     log('1.5 results: ', results);
    86 });
    87 //26.993> a start
    88 //26.996> b start
    89 //27.200> c start
    90 //27.202> d start
    91 //27.313> e start
    92 //27.809> 1.5 err:
    93 //27.810> 1.5 results: { a: 'a400', b: 'b200', c: 'c100', e: 'e300', d: 'd600' }
    View Code

    whilst: 相当于while,但其中的异步调用将在完成后才会进行下一次循环。
    doWhilst: 相当于do…while, doWhilst交换了fn,test的参数位置,先执行一次循环,再做test判断。
    until: until与whilst正好相反,当test为false时循环,与true时跳出。其它特性一致。
    doUntil: doUntil与doWhilst正好相反,当test为false时循环,与true时跳出。其它特性一致。
    forever: 无论条件循环执行,如果不出错,callback永远不被执行。

      1 var async = require('async');
      2 var t = require('./t');
      3 var log = t.log;
      4 
      5 /**
      6  * 该函数的功能比较简单,条件变量通常定义在外面,可供每个函数访问。在循环中,异步调用时产生的值实际上被丢弃了,因为最后那个callback只能传入错误信息。
      7  *
      8  * 另外,第二个函数fn需要能接受一个函数cb,这个cb最终必须被执行,用于表示出错或正常结束。
      9  */
     10 // whilst(test, fn, callback)
     11 
     12 /**
     13 * 正常情况,没有出错。第二个函数虽然是异步调用,但被同步执行。所以第三个函数被调用时,已经过了3秒。
     14 */
     15 // 1.1
     16 var count1 = 0;
     17 async.whilst(
     18     function() { return count1 < 3 },
     19     function(cb) {
     20         log('1.1 count: ', count1);
     21         count1++;
     22         setTimeout(cb, 1000);
     23     },
     24     function(err) {
     25         // 3s have passed
     26         log('1.1 err: ', err);
     27     }
     28 );
     29 //10.318> 1.1 count: 0
     30 //11.330> 1.1 count: 1
     31 //12.342> 1.1 count: 2
     32 //13.356> 1.1 err:
     33 
     34 
     35 /**
     36 * 中途出错。出错后立刻调用第三个函数。
     37 */
     38 // 1.2
     39 var count2 = 0;
     40 async.whilst(
     41     function() { return count2 < 3 },
     42     function(cb) {
     43         log('1.2 count: ', count2);
     44         if(count2===1) {
     45             t.err('myerr', cb, 200);
     46         } else {
     47             count2++;
     48             setTimeout(cb, 1000);
     49         }
     50     },
     51     function(err) {
     52         // 2s have passed
     53         log('1.2 err: ', err);
     54     }
     55 );
     56 //12.805> 1.2 count: 0
     57 //13.824> 1.2 count: 1
     58 //14.026> 1.2 err: myerr
     59 
     60 /**
     61 * 第二个函数即使产生值,也会被忽略。第三个函数只能得到err。
     62 */
     63 // 1.3
     64 var count3 = 0;
     65 async.whilst(
     66     function() {return count3 < 3 },
     67     function(cb) {
     68         log('1.3 count: ', count3);
     69         t.inc(count3++, cb);
     70     },
     71     function(err,result){ // result没有用
     72         log('1.3 err: ', err);
     73         log('1.3 result: ', result);
     74     }
     75 );
     76 //45.311> 1.3 count: 0
     77 //45.514> 1.3 count: 1
     78 //45.718> 1.3 count: 2
     79 //45.920> 1.3 err:
     80 //45.923> 1.3 result:
     81 
     82 /**
     83 *  doWhilst交换了fn,test的参数位置,先执行一次循环,再做test判断。 和javascript中do..while语法一致。
     84 */
     85 // doWhilst(fn, test, callback)
     86 //1.4
     87 var count4 = 0;
     88 async.doWhilst(
     89     function(cb) {
     90         log('1.4 count: ', count4);
     91         t.inc(count4++, cb);
     92     },
     93     function() { log("1.4 test"); return count4 < 3 },
     94     function(err,result){ // result没有用
     95         log('1.4 err: ', err);
     96         log('1.4 result: ', result);
     97     }
     98 );
     99 //33.643> 1.4 count: 0
    100 //33.848> 1.4 test
    101 //33.850> 1.4 count: 1
    102 //34.054> 1.4 test
    103 //34.057> 1.4 count: 2
    104 //34.269> 1.4 test
    105 //34.270> 1.4 err:
    106 //34.270> 1.4 result:
    107 
    108 /**
    109 * until与whilst正好相反,当test为false时循环,与true时跳出。其它特性一致。
    110 */
    111 // 1.5
    112 var count5 = 0;
    113 async.until(
    114     function() { return count5>3 },
    115     function(cb) {
    116         log('1.5 count: ', count5);
    117         count5++;
    118         setTimeout(cb, 200);
    119     },
    120     function(err) {
    121         // 4s have passed
    122         log('1.5 err: ',err);
    123     }
    124 );
    125 //42.498> 1.5 count: 0
    126 //42.701> 1.5 count: 1
    127 //42.905> 1.5 count: 2
    128 //43.107> 1.5 count: 3
    129 //43.313> 1.5 err:
    130 
    131 /**
    132 * doUntil与doWhilst正好相反,当test为false时循环,与true时跳出。其它特性一致。
    133 */
    134 // doUntil(fn, test, callback)
    135 // 1.6
    136 var count6 = 0;
    137 async.doUntil(
    138     function(cb) {
    139         log('1.6 count: ', count6);
    140         count6++;
    141         setTimeout(cb, 200);
    142     },
    143     function() { log('1.6 test');return count6>3 },
    144     function(err) {
    145         // 4s have passed
    146         log('1.6 err: ',err);
    147     }
    148 );
    149 //41.831> 1.6 count: 0
    150 //42.035> 1.6 test
    151 //42.037> 1.6 count: 1
    152 //42.241> 1.6 test
    153 //42.244> 1.6 count: 2
    154 //42.456> 1.6 test
    155 //42.457> 1.6 count: 3
    156 //42.660> 1.6 test
    157 //42.661> 1.6 err:
    158 
    159 /**
    160  * forever,无论条件循环执行,如果不出错,callback永远不被执行
    161  */
    162 //forever(fn, callback)
    163 //1.7
    164 var count7 = 0;
    165 async.forever(
    166     function(cb) {
    167         log('1.7 count: ', count7);
    168         count7++;
    169         setTimeout(cb, 200);
    170     },
    171     function(err) {
    172         log('1.7 err: ',err);
    173     }
    174 );
    175 //52.770> 1.7 count: 0
    176 //52.973> 1.7 count: 1
    177 //53.175> 1.7 count: 2
    178 //53.377> 1.7 count: 3
    179 //53.583> 1.7 count: 4
    180 //53.785> 1.7 count: 5
    181 //53.987> 1.7 count: 6
    182 //54.189> 1.7 count: 7
    183 //54.391> 1.7 count: 8
    184 //54.593> 1.7 count: 9
    185 //54.795> 1.7 count: 10
    186 //54.997> 1.7 count: 11
    187 //55.199> 1.7 count: 12
    View Code

    waterfall: 按顺序依次执行一组函数。每个函数产生的值,都将传给下一个。

     1 var async = require('async');
     2 var t = require('./t');
     3 var log = t.log;
     4 
     5 /**
     6  *  这个函数名为waterfall(瀑布),可以想像瀑布从上到下,中途冲过一层层突起的石头。
     7  *
     8  * 注意,该函数不支持json格式的tasks
     9  */
    10 // async.waterfall(tasks, [callback]);
    11 
    12 /**
    13  * 所有函数正常执行,每个函数的结果都将变为下一个函数的参数。
    14  *
    15  * 注意,所有的callback都必须形如callback(err, result),但err参数在前面各函数中无需声明,它被自动处理。
    16  */
    17 // 1.1
    18 async.waterfall([
    19     function(cb) { log('1.1.1: ', 'start'); cb(null, 3); },
    20     function(n, cb) { log('1.1.2: ',n); t.inc(n, cb); },
    21     function(n, cb) { log('1.1.3: ',n); t.fire(n*n, cb); }
    22 ], function (err, result) {
    23     log('1.1 err: ', err);
    24     log('1.1 result: ', result);
    25 });
    26 //31.749> 1.1.1: start
    27 //31.752> 1.1.2: 3
    28 //31.953> 1.1.3: 4
    29 //32.156> 1.1 err: null
    30 //32.159> 1.1 result: 16
    31 
    32 /**
    33 * 中途有函数出错,其err直接传给最终callback,结果被丢弃,后面的函数不再执行。
    34 */
    35 // 1.2
    36 async.waterfall([
    37     function(cb) { log('1.2.1: ', 'start'); cb(null, 3); },
    38     function(n, cb) { log('1.2.2: ', n); t.inc(n, cb); },
    39     function(n, cb) { log('1.2.3: ', n); t.err('myerr', cb); },
    40     function(n, cb) { log('1.2.4: ', n); t.fire(n, cb); }
    41 ], function (err, result) {
    42     log('1.2 err: ', err);
    43     log('1.2 result: ', result);
    44 });
    45 //44.935> 1.2.1: start
    46 //44.939> 1.2.2: 3
    47 //45.140> 1.2.3: 4
    48 //45.344> 1.2 err: myerr
    49 //45.348> 1.2 result:
    50 
    51 /**
    52 * 注意: 以json形式传入tasks,将不会被执行!!
    53 */
    54 async.waterfall({
    55     a: function(cb) { log('1.3.1: ', 'start'); cb(null, 3); },
    56     b: function(n, cb) { log('1.3.2: ', n); t.inc(n, cb); },
    57     c: function(n, cb) { log('1.3.3: ', n); t.fire(n*n, cb); }
    58 }, function (err, result) {
    59     log('1.3 err: ', err);
    60     log('1.3 result: ', result);
    61 });
    62 //49.222> 1.3 err: [Error: First argument to waterfall must be an array of functions]
    63 //49.228> 1.3 result:
    View Code

    compose: 创建一个包括一组异步函数的函数集合,每个函数会消费上一次函数的返回值。把f(),g(),h()异步函数,组合成f(g(h()))的形式,通过callback得到返回值。

     1 var async = require('async');
     2 var t = require('./t');
     3 var log = t.log;
     4 
     5 // compose(fn1, fn2...)
     6 
     7 /**
     8  * 通过compose组合,f(g(h()))的形式,从内层到外层的执行的顺序。
     9  */
    10 //1.1
    11 function f(n,callback){
    12     log('1.1.f enter: ',n);
    13     setTimeout(function () {
    14         callback(null, n + 1);
    15     }, 10);
    16 }
    17 function g(n, callback) {
    18     log('1.1.g enter: ',n);
    19     setTimeout(function () {
    20         callback(null, n * 2);
    21     }, 10);
    22 }
    23 function h(n, callback) {
    24     log('1.1.h enter: ',n);
    25     setTimeout(function () {
    26         callback(null, n - 10);
    27     }, 10);
    28 }
    29 var fgh = async.compose(f,g,h);
    30 fgh(4,function(err,result){
    31     log('1.1 err: ', err);
    32     log('1.1 result: ', result);
    33 });
    34 //05.307> 1.1.h enter: 4
    35 //05.329> 1.1.g enter: -6
    36 //05.341> 1.1.f enter: -12
    37 //05.361> 1.1 err: null
    38 //05.362> 1.1 result: -11
    View Code

    applyEach: 实现给一数组中每个函数传相同参数,通过callback返回。如果只传第一个参数,将返回一个函数对象,我可以传参调用。

     1 var async = require('async');
     2 var t = require('./t');
     3 var log = t.log;
     4 
     5 // applyEach(fns, args..., callback)
     6 
     7 /**
     8  * 异步执行,给数组中的函数,他们有相同的参数。
     9  */
    10 //1.1
    11 async.applyEach([
    12     function (name,cb) {
    13         setTimeout(function () {
    14             log("1.1 handler: " + name + " A");
    15             cb(null, name);
    16         }, 500);
    17     }, function (name,cb) {
    18         setTimeout(function () {
    19             log("1.1 handler: " + name + " B");
    20             cb(null, name);
    21         }, 150);
    22     }
    23 ], 'Hello', function (err) {
    24     log('1.1 err: ', err);
    25 });
    26 //06.739> 1.1 handler: Hello B
    27 //07.079> 1.1 handler: Hello A
    28 //07.080> 1.1 err: null
    29 
    30 /**
    31  *  异步执行,当只设置第一参数后,得到函数对象,再传参调用这个函数。
    32  */
    33 //1.2
    34 var fn = async.applyEach([
    35     function (name,cb) {
    36         setTimeout(function () {
    37             log("1.2 handler: " + name + " A");
    38         }, 500);
    39     }, function (name,cb) {
    40         setTimeout(function () {
    41             log("1.2 handler: " + name + " B");
    42         }, 150);
    43     }
    44 ]);
    45 fn("simgle",function(err){
    46     log('err: ',err);
    47 });
    48 //29.351> 1.2 handler: simgle B
    49 //29.688> 1.2 handler: simgle A
    50 
    51 /**
    52  *   applyEachSeries与applyEach唯一不同的是,数组的函数同步执行。
    53  */
    54 //applyEachSeries(arr, args..., callback)
    55 //1.3
    56 async.applyEachSeries([
    57     function (name,cb) {
    58         setTimeout(function () {
    59             log("1.3 handler: " + name + " A");
    60             cb(null, name);
    61         }, 500);
    62     }, function (name,cb) {
    63         setTimeout(function () {
    64             log("1.3 handler: " + name + " B");
    65             cb(null, name);
    66         }, 150);
    67     }
    68 ], "aaa", function (err) {
    69     log('1.3 err: ', err);
    70 });
    71 //10.669> 1.3 handler: aaa A
    72 //10.831> 1.3 handler: aaa B
    73 //10.834> 1.3 err: null
    View Code

    queue: 是一个串行的消息队列,通过限制了worker数量,不再一次性全部执行。当worker数量不够用时,新加入的任务将会排队等候,直到有新的worker可用。

      1 var async = require('async');
      2 var t = require('./t');
      3 var log = t.log;
      4 
      5 /*
      6  * 该函数有多个点可供回调,如worker用完时、无等候任务时、全部执行完时等。
      7  */
      8 // queue(worker, concurrency)
      9 
     10 /**
     11  * 定义一个queue,设worker数量为2
     12  */
     13 var q = async.queue(function(task, callback) {
     14     log('worker is processing task: ', task.name);
     15     task.run(callback);
     16 }, 2);
     17 
     18 /**
     19  * 监听:如果某次push操作后,任务数将达到或超过worker数量时,将调用该函数
     20  */
     21 q.saturated = function() {
     22     log('all workers to be used');
     23 }
     24 
     25 /**
     26  * 监听:当最后一个任务交给worker时,将调用该函数
     27  */
     28 q.empty = function() {
     29     log('no more tasks wating');
     30 }
     31 
     32 /**
     33  * 监听:当所有任务都执行完以后,将调用该函数
     34  */
     35 q.drain = function() {
     36     log('all tasks have been processed');
     37 }
     38 
     39 /**
     40 * 独立加入2个任务
     41 */
     42 q.push({name:'t1', run: function(cb){
     43     log('t1 is running, waiting tasks: ', q.length());
     44     t.fire('t1', cb, 400); // 400ms后执行
     45 }}, function(err) {
     46     log('t1 executed');
     47 });
     48 log('pushed t1, waiting tasks: ', q.length());
     49 
     50 q.push({name:'t2',run: function(cb){
     51     log('t2 is running, waiting tasks: ', q.length());
     52     t.fire('t2', cb, 200); // 200ms后执行
     53 }}, function(err) {
     54     log('t2 executed');
     55 });
     56 log('pushed t2, waiting tasks: ', q.length());
     57 //54.448> pushed t1, waiting tasks: 1
     58 //54.451> all workers to be used
     59 //54.452> pushed t2, waiting tasks: 2
     60 //54.452> worker is processing task: t1
     61 //54.453> t1 is running, waiting tasks: 1
     62 //54.455> no more tasks wating
     63 //54.455> worker is processing task: t2
     64 //54.455> t2 is running, waiting tasks: 0
     65 //54.656> t2 executed
     66 //54.867> t1 executed
     67 //54.868> all tasks have been processed
     68 
     69 
     70 // 同时加入多个任务
     71 q.push([
     72     {
     73         name:'t3', run: function(cb){
     74             log('t3 is running, waiting tasks: ', q.length());
     75             t.fire('t3', cb, 300); // 300ms后执行
     76         }
     77     },{
     78         name:'t4', run: function(cb){
     79             log('t4 is running, waiting tasks: ', q.length());
     80             t.fire('t4', cb, 500); // 500ms后执行
     81         }
     82     },{
     83         name:'t5', run: function(cb){
     84             log('t5 is running, waiting tasks: ', q.length());
     85             t.fire('t5', cb, 100); // 100ms后执行
     86         }
     87     },{
     88         name:'t6', run: function(cb){
     89             log('t6 is running, waiting tasks: ', q.length());
     90             t.fire('t6', cb, 400); // 400ms后执行
     91         }
     92     }
     93 ], function(err) {
     94     log('err: ',err);
     95 });
     96 log('pushed t3,t4,t5,t6 into queue, waiting tasks: ', q.length());
     97 //53.755> all workers to be used
     98 //53.758> pushed t3,t4,t5,t6 into queue, waiting tasks: 4
     99 //53.759> worker is processing task: t3
    100 //53.760> t3 is running, waiting tasks: 3
    101 //53.762> worker is processing task: t4
    102 //53.762> t4 is running, waiting tasks: 2
    103 //54.073> err: null
    104 //54.074> worker is processing task: t5
    105 //54.076> t5 is running, waiting tasks: 1
    106 //54.183> err: null
    107 //54.184> no more tasks wating
    108 //54.185> worker is processing task: t6
    109 //54.186> t6 is running, waiting tasks: 0
    110 //54.265> err: null
    111 //54.588> err: null
    112 //54.589> all tasks have been processed
    View Code

    cargo: 一个串行的消息队列,类似于queue,通过限制了worker数量,不再一次性全部执行。不同之处在于,cargo每次会加载满额的任务做为任务单元,只有任务单元中全部执行完成后,才会加载新的任务单元。

     1 var async = require('async');
     2 var t = require('./t');
     3 var log = t.log;
     4 
     5 // cargo(worker, [payload])
     6 
     7 /**
     8  * 创建cargo实例
     9  */
    10 var cargo = async.cargo(function (tasks, callback) {
    11     for(var i=0; i<tasks.length; i++){
    12         log('start ' + tasks[i].name);
    13     }
    14     callback();
    15 }, 2);
    16 
    17 
    18 /**
    19  * 监听:如果某次push操作后,任务数将达到或超过worker数量时,将调用该函数
    20  */
    21 cargo.saturated = function() {
    22     log('all workers to be used');
    23 }
    24 
    25 /**
    26  * 监听:当最后一个任务交给worker时,将调用该函数
    27  */
    28 cargo.empty = function() {
    29     log('no more tasks wating');
    30 }
    31 
    32 /**
    33  * 监听:当所有任务都执行完以后,将调用该函数
    34  */
    35 cargo.drain = function() {
    36     log('all tasks have been processed');
    37 }
    38 
    39 /**
    40  * 增加新任务
    41  */
    42 cargo.push({name: 'A'}, function (err) {
    43     t.wait(300);
    44     log('finished processing A');
    45 });
    46 cargo.push({name: 'B'}, function (err) {
    47     t.wait(600);
    48     log('finished processing B');
    49 });
    50 cargo.push({name: 'C'}, function (err) {
    51     t.wait(500);
    52     log('finished processing C');
    53 });
    54 cargo.push({name: 'D'}, function (err) {
    55     t.wait(100);
    56     log('finished processing D');
    57 });
    58 cargo.push({name: 'E'}, function (err) {
    59     t.wait(200);
    60     log('finished processing E');
    61 });
    62 //40.016> all workers to be used
    63 //40.020> no more tasks wating
    64 //40.020> start A
    65 //40.020> start B
    66 //40.322> finished processing A
    67 //40.923> finished processing B
    68 //40.923> no more tasks wating
    69 //40.924> start C
    70 //40.924> start D
    71 //41.425> finished processing C
    72 //41.526> finished processing D
    73 //41.526> no more tasks wating
    74 //41.527> start E
    75 //41.728> finished processing E
    76 //41.728> all tasks have been processed
    77 //41.729> all tasks have been processed
    78 //41.729> all tasks have been processed
    79 //41.729> all tasks have been processed
    80 //41.730> all tasks have been processed
    View Code

    auto: 用来处理有依赖关系的多个任务的执行。

      1 var async = require('async');
      2 var t = require('./t');
      3 var log = t.log;
      4 
      5 /**
      6  * 比如某些任务之间彼此独立,可以并行执行;但某些任务依赖于其它某些任务,只能等那些任务完成后才能执行。
      7  * 虽然我们可以使用parallel和series结合起来实现该功能,但如果任务之间关系复杂,则代码会相当复杂,以后如果想添加一个新任务,也会很麻烦。
      8  * 这时使用auto,则会事半功倍。
      9  *
     10  * 如果有任务中途出错,则会把该错误传给最终callback,所有任务(包括已经执行完的)产生的数据将被忽略。
     11  * 如果不关心错误和最终数据,可以不用写最后那个callback。
     12  */
     13 // async.auto(tasks, [callback])
     14 
     15 /**
     16  * 我要写一个程序,它要完成以下几件事:
     17  * 1. 从某处取得数据
     18  * 2. 在硬盘上建立一个新的目录
     19  * 3. 将数据写入到目录下某文件
     20  * 4. 发送邮件,将文件以附件形式发送给其它人。
     21  *
     22  * 分析该任务,可以知道1与2可以并行执行,3需要等1和2完成,4要等3完成。
     23  * 可以按以下方式来使用auto函数。
     24  */
     25 // 1.1
     26 async.auto({
     27     getData: function (callback) {
     28         setTimeout(function(){
     29             console.log('1.1: got data');
     30              callback(null, 'mydata');
     31         }, 300);
     32     },
     33     makeFolder: function (callback) {
     34         setTimeout(function(){
     35             console.log('1.1: made folder');
     36             callback(null, 'myfolder');
     37         }, 200);
     38     },
     39     writeFile: ['getData', 'makeFolder', function(callback) {
     40         setTimeout(function(){
     41             console.log('1.1: wrote file');
     42             callback(null, 'myfile');
     43         }, 300);
     44     }],
     45     emailFiles: ['writeFile', function(callback, results) {
     46         log('1.1: emailed file: ', results.writeFile);
     47         callback(null, results.writeFile);
     48     }]
     49 }, function(err, results) {
     50     log('1.1: err: ', err);
     51     log('1.1: results: ', results);
     52 });
     53 //1.1: made folder
     54 //1.1: got data
     55 //1.1: wrote file
     56 //20.120> 1.1: emailed file: myfile
     57 //20.125> 1.1: err: null
     58 //20.127> 1.1: results: { makeFolder: 'myfolder',
     59 //    getData: 'mydata',
     60 //    writeFile: 'myfile',
     61 //    emailFiles: 'myfile' }
     62 
     63 
     64 
     65 /**
     66 * 如果中途出错,则会把错误交给最终callback,执行完任务的传给最终callback。未执行完成的函数值被忽略
     67 */
     68 // 1.2
     69 async.auto({
     70     getData: function (callback) {
     71         setTimeout(function(){
     72             console.log('1.2: got data');
     73             callback(null, 'mydata');
     74         }, 300);
     75     },
     76     makeFolder: function (callback) {
     77         setTimeout(function(){
     78             console.log('1.2: made folder');
     79             callback(null, 'myfolder');
     80         }, 200);
     81     },
     82     writeFile: ['getData', 'makeFolder', function(callback, results) {
     83         setTimeout(function(){
     84             console.log('1.2: wrote file');
     85             callback('myerr');
     86         }, 300);
     87     }],
     88     emailFiles: ['writeFile', function(callback, results) {
     89         console.log('1.2: emailed file: ' + results.writeFile);
     90         callback('err sending email', results.writeFile);
     91     }]
     92 }, function(err, results) {
     93     log('1.2 err: ', err);
     94     log('1.2 results: ', results);
     95 });
     96 //1.2: made folder
     97 //1.2: got data
     98 //1.2: wrote file
     99 //51.399> 1.2 err: myerr
    100 //51.401> 1.2 results: { makeFolder: 'myfolder',
    101 //    getData: 'mydata',
    102 //    writeFile: undefined }
    View Code

    iterator: 将一组函数包装成为一个iterator,初次调用此iterator时,会执行定义中的第一个函数并返回第二个函数以供调用。

     1 var async = require('async');
     2 var t = require('./t');
     3 var log = t.log;
     4 
     5 /**
     6  * 也可通过手动调用 next() 得到以下一个函数为起点的新的iterator。
     7  * 该函数通常由async在内部使用,但如果需要时,也可在我们的代码中使用它。
     8  */
     9 // async.iterator(tasks)
    10 
    11 var iter = async.iterator([
    12     function () {log('I am 111')},
    13     function () {log('I am 222')},
    14     function () {log('I am 333')}
    15 ]);
    16 
    17 /**
    18 * 直接调用(),会执行当前函数,并返回一个由下个函数为起点的新的iterator
    19 */
    20 //1.1
    21 log('1.1 iter()');
    22 var it1 = iter();
    23 it1();
    24 it1();
    25 //28.368> 1.1 iter()
    26 //28.371> I am 111
    27 //28.372> I am 222
    28 //28.372> I am 222
    29 
    30 /**
    31 * 通过iter()来调用下一个函数
    32 */
    33 log('1.2 iter()');
    34 var it2 = iter();
    35 var it3 = it2();
    36 var it4 = it3();
    37 //it4(); // 这句代码执行会报错
    38 log(it4); // => 'null'
    39 //32.449> 1.2 iter()
    40 //32.452> I am 111
    41 //32.452> I am 222
    42 //32.453> I am 333
    43 //32.454> null
    44 
    45 /**
    46  * 调用next(),不会执行当前函数,直接返回由下个函数为起点的新iterator
    47  * 对于同一个iterator,多次调用next(),不会影响自己
    48  */
    49 //1.3
    50 log('1.3 iter()');
    51 var it5 = iter.next();
    52 it5();
    53 var it6 = iter.next().next();
    54 it6();
    55 iter();
    56 //39.895> 1.3 iter()
    57 //39.898> I am 222
    58 //39.899> I am 333
    59 //39.899> I am 111
    View Code

    apply: 可以让我们给一个函数预绑定多个参数并生成一个可直接调用的新函数,简化代码。

     1 var async = require('async');
     2 
     3 var t = require('./t');
     4 var log = t.log;
     5 
     6 /**
     7  * function(callback) { t.inc(3, callback); }
     8  * 等价于:
     9  * async.apply(t.inc, 3);
    10  */
    11 // apply(function, arguments..)
    12 
    13 /**
    14  * 通过名字绑定函数t.inc, t.fire,作为新函数给parallel调用
    15  */
    16 //1.1
    17 async.parallel([
    18     async.apply(t.inc, 3),
    19     async.apply(t.fire, 100)
    20 ], function (err, results) {
    21     log('1.1 err: ', err);
    22     log('1.1 results: ', results);
    23 });
    24 //58.605> 1.1 err: null
    25 //58.613> 1.1 results: [ 4, 100 ]
    26 
    27 /**
    28  * 构造一个加法函数,通过apply简化代码
    29  */
    30 //1.2
    31 function inc(a,b,callback,timeout){
    32     var timeout = timeout || 200;
    33     t.wait(200);
    34     setTimeout(function() {
    35         callback(null, a+b);
    36     }, timeout);
    37 }
    38 var fn = async.apply(inc, 1, 2);
    39 fn(function(err, n){
    40     log('1.2 inc: ' + n);
    41 });
    42 //58.616> 1.2 inc: 3
    View Code

    nextTick: 与nodejs的nextTick一样,再最后调用函数。

     1 var async = require('async');
     2 var t = require('./t');
     3 var log = t.log;
     4 
     5 /**
     6  * 但在浏览器端,只能使用setTimeout(callback,0),但这个方法有时候会让其它高优先级的任务插到前面去。
     7  * 所以提供了这个nextTick,让同样的代码在服务器端和浏览器端表现一致。
     8  */
     9 // nextTick(callback)
    10 
    11 var calls = [];
    12 async.nextTick(function() {
    13     calls.push('two');
    14 });
    15 async.nextTick(function() {
    16     log('1.1',calls);
    17 });
    18 calls.push('one');
    19 log('1.2',calls);
    20 async.nextTick(function() {
    21     log('1.3',calls);
    22 });
    23 //09.838> 1.2[ 'one' ]
    24 //09.842> 1.1[ 'one', 'two' ]
    25 //09.843> 1.3[ 'one', 'two' ]
    View Code

    times: 异步运行,times可以指定调用几次,并把结果合并到数组中返回
    timesSeries: 与time类似,唯一不同的是同步执行

     1 var async = require('async');
     2 var t = require('./t');
     3 var log = t.log;
     4 
     5 // times(n, callback)
     6 
     7 function delay(n){return (n+12) % 7 *100;}
     8 var createUser = function(id, callback) {
     9     callback(null, {
    10         id: 'user' + id,
    11         delay:delay(id)
    12     })
    13 }
    14 
    15 /**
    16  * 异步执行,调用3次createUser函数,结果被合并到数组返回
    17  */
    18 //1.1
    19 async.times(3, function(n, callback){
    20     log("1.1 enter: "+ n);
    21     setTimeout(function(){
    22         log('1.1 handler: ',n);
    23         createUser(n, function(err, user) {
    24             callback(err, user)
    25         })
    26     },delay(n));
    27 }, function(err, users) {
    28     log('1.1 err: ',err);
    29     log('1.1 result: ',users);
    30 });
    31 //07.397> 1.1 enter: 0
    32 //07.400> 1.1 enter: 1
    33 //07.401> 1.1 enter: 2
    34 //07.412> 1.1 handler: 2
    35 //07.912> 1.1 handler: 0
    36 //08.009> 1.1 handler: 1
    37 //08.010> 1.1 err: null
    38 //08.011> 1.1 result: [ { id: 'user0', delay: 500 },
    39 //    { id: 'user1', delay: 600 },
    40 //    { id: 'user2', delay: 0 } ]
    41 
    42 /**
    43 *  timesSeries与time唯一不同的是,同步执行
    44 */
    45 //timesSeries(n, callback)
    46 
    47 /**
    48  * 同步执行,调用3次createUser函数,结果被合并到数组返回
    49  */
    50 //1.2
    51 async.timesSeries(3, function(n, callback){
    52     log("1.2 enter: "+ n);
    53     setTimeout(function(){
    54         log('1.2 handler: ',n);
    55         createUser(n, function(err, user) {
    56             callback(err, user)
    57         })
    58     },delay(n));
    59 }, function(err, users) {
    60     log('1.2 err: ',err);
    61     log('1.2 result: ',users);
    62 });
    63 //16.642> 1.2 enter: 0
    64 //17.159> 1.2 handler: 0
    65 //17.162> 1.2 enter: 1
    66 //17.763> 1.2 handler: 1
    67 //17.767> 1.2 enter: 2
    68 //17.778> 1.2 handler: 2
    69 //17.779> 1.2 err: null
    70 //17.780> 1.2 result: [ { id: 'user0', delay: 500 },
    71 //    { id: 'user1', delay: 600 },
    72 //    { id: 'user2', delay: 0 } ]
    View Code
    • Utils

    memoize: 让某一个函数在内存中缓存它的计算结果。对于相同的参数,只计算一次,下次就直接拿到之前算好的结果。
    unmemoize: 让已经被缓存的函数,返回不缓存的函数引用。
    log: 执行某异步函数,并记录它的返回值,日志输出。
    dir: 与log类似,不同之处在于,会调用浏览器的console.dir()函数,显示为DOM视图。
    fire: 直接将obj的内容返回给async
    err: 模拟一个错误的产生,让async各个函数末尾的callback接收到。
    wait: 刻意等待mils的时间,mils的单位是毫秒。

  • 相关阅读:
    外键的缺陷
    laravel 关联模型
    n的阶乘末尾出现的次数
    JavaScript的self和this使用小结
    cocos2dx中的内存管理方式
    c++ 与 lua 简单交互参数介绍
    c++的单例模式及c++11对单例模式的优化
    cocos2dx帧动画
    cocos2dx中坐标系
    cocos2dx中替代goto的用法:do{}while(0)和CC_BREAK_IF
  • 原文地址:https://www.cnblogs.com/huair_12/p/4117351.html
Copyright © 2011-2022 走看看