Async.js常用方法整理之Collections

Published: 2015-11-18

Tags: Node.js Async

本文总阅读量
  1. each
  2. forEachOf
  3. map
  4. filter
  5. reject
  6. sortBy
  7. some/any
  8. every/all

Collections (集合)

1. each

each - 对同一个集合之中的所有元素都执行同一个异步操作

Template 1

async.each([0,1,2,3,4,5,6,7,8,9], function(item, callback) {
  setTimeout(function() {
    console.log('>', item);
    callback();
  }, 2 * Math.random() * 1000);
}, function(err) {
  console.log('> done');
});

console.log(':)');

Output 1

:)
> 4
> 5
> 2
> 7
> 8
> 3
> 0
> 1
> 9
> 6
> done

Template 2

async.each([0,1,2,3,4,5,6,7,8,9], function(item, callback) {
  setTimeout(function() {
    console.log('>', item);
    if (item === 3) {
      callback("error: This item eque 3");
    }
    else {
      callback();
    }
  }, 2 * Math.random() * 1000);
}, function(err) {
  if (err) {
    console.log('some error');
    console.log(err);
  }
  else {
    console.log('success');
  }
  console.log('> done');
});

console.log(':)');

Output 2

:)
> 9
> 2
> 8
> 0
> 4
> 5
> 3
some error
error: This item eque 3
> done
> 1
> 6
> 7

综合如上的两个例子,可得出在分别处理集合元素的过程中,传入callback()的信息会当作error经由回调用函数处理,不传递参数的callback()则视为执行成功,如果集合中没有没有任何错误,那么最终会调用一次回调函数,比如Template 1中输出> done

还有一个地方值的一说

上图所示为官方的文档,网址:https://github.com/caolan/async

关于集合的操作方法中大多都分为两种,比如之前介绍的each,可以分为eachSeries和eachLimit两种

Template 3

async.each([0,1,2,3,4,5,6,7,8,9], function(item, callback) {
  if (item === 3) {
    setTimeout(function () {
      console.log('>', item);
      callback();
    }, 1000);
  }
  else {
    console.log('>', item);
    callback();
  }
}, function(err) {
  console.log('> done');
});

console.log(':)');

Output 3

> 0
> 1
> 2
> 4
> 5
> 6
> 7
> 8
> 9
:)
> 3
> done

Template 4

async.eachSeries([0,1,2,3,4,5,6,7,8,9], function(item, callback) {
  if (item === 3) {
    setTimeout(function () {
      console.log('>', item);
      callback();
    }, 1000);
  }
  else {
    console.log('>', item);
    callback();
  }
}, function(err) {
  console.log('> done');
});

console.log(':)');

Output 4

> 0
:)
> 1
> 2
> 3
> 4
> 5
> 6
> 7
> 8
> 9
> done

Template 5

async.eachLimit([0,1,2,3,4,5,6,7,8,9], 1, function(item, callback) {
  if (item === 3) {
    setTimeout(function () {
      console.log('>', item);
      callback();
    }, 1000);
  }
  else {
    console.log('>', item);
    callback();
  }
}, function(err) {
  console.log('> done');
});

console.log(':)');

Output 5

> 0
> 1
> 2
:)
> 3
> 4
> 5
> 6
> 7
> 8
> 9
> done

Template 6

async.eachLimit([0,1,2,3,4,5,6,7,8,9], 3, function(item, callback) {
  if (item === 3) {
    setTimeout(function () {
      console.log('>', item);
      callback();
    }, 1000);
  }
  else {
    console.log('>', item);
    callback();
  }
}, function(err) {
  console.log('> done');
});

console.log(':)');

Output 6

> 0
> 1
> 2
> 4
> 5
> 6
> 7
> 8
> 9
:)
> 3
> done

上边共四个例子,一个是each,一个是eachSeries,另外两个是eachLimit不同参数的

结果可知,each为异步执行的,eachSeries为同步执行的,可以保证执行顺序与列表顺序相应,当eachLimit设置限制为1时表现与eachSeries相同,不为1时则与each相同

可能那个笑脸大家也注意到了,位置出现的不同,我解释不了,只能说可能是因为不同函数的实现导致,想把这个笑脸最后输出,按照代码的顺序,就需要其它控制函数

还有一个很重要的注意事项,同步执行的情况下,如果出现错误则会终止,并执行回调函数,异步情况下则不受影响


2. forEachOf

forEachOf - 对同一个集合之中的所有元素都执行同一个异步操作,类似于each,可以传递key与value两个值

Template 7

var obj = {one: '1', two: '2', three: '3'};

async.forEachOf(obj, function (value, key, callback) {
  console.log(key, value);
  callback();
}, function (err) {
  if (err) console.log(err);
  console.log("> done");
})

Output 7

one 1
two 2
three 3
> done

forEachOf也是有两种相关函数,forEachOfSeries与forEachOfLimit,类比于each,此处以及以后不再提及


3. map

map - 提供一个新的数组来存储处理后的结果,它的callback的函数第一个参数接收error,第二个参数用来返回处理后的值

Template 8

async.map([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], function (item, callback) {
  if (item === 3) {
    setTimeout(function () {
      callback(null, item + 10)
    }, 1000);
  }
  else {
    callback(null, item + 10)
  }
}, function (err, result) {
  console.log(result);
});

Output 8

[ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 ]

文档中提及,函数不保证每个元素按照顺序处理完成,但是可以保证新生成的顺序顺序与原数组保持一致


4. filter

filter - 过滤数组中的元素,iterator的回调中只接受true或false

Template 9

async.filter([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], function (item, callback) {
  if (item % 2 === 0) {
    callback(true);
  }
  else {
    callback(false);
  }
}, function (results) {
  console.log(results);
})

Output 9

[ 0, 2, 4, 6, 8 ]

5. reject

reject - 与filter的作用正好相反,剔除通过验证的值


6. sortBy

sortBy - 排序,回调中返回排序后的数组

Template 10

// 正序排序
async.sortBy([1,9,3,5], function(x, callback){
  callback(null, x);
}, function(err,result){
  console.log(result);
});

// 逆序排序
async.sortBy([1,9,3,5], function(x, callback){
    callback(null, x*-1);    
}, function(err,result){
  console.log(result);
});

Output 10

[ 1, 3, 5, 9 ]
[ 9, 5, 3, 1 ]


7. some/any

some - 如果存在执行成功的则result为true,否则为false

async.some(['file1','file2','file3'], fs.exists, function(result){
    // if result is true then at least one of the files exists
});

8. every/all

every - 如果所有都执行成功则result为true,否则为false

async.every(['file1','file2','file3'], fs.exists, function(result){
    // if result is true then every file exists
});

集合部分我觉得常用的就这么些了,async在处理数组方面真是挺不错的。