Neo-Async


![NEO_async_3.png](https://qiita-image-store.s3.amazonaws.com/0/17390/5c8b9bf6-b151-41e4-9453-c472b64e5e4e.png "NEO_async_3.png")

## 目次

* Async.jsとは
* Neo-Async.jsとは
* 作った経緯
* 速度比較
* 機能一覧
* 今後の予定

## Async.jsとは

* jsで非同期系の処理をすると言えばスタンダードなライブラリ
* githubで★が１万超え

## Neo-Async.jsとは

* Asyncより速い
* Asyncに完全に互換性がある
* ほぼ全てのメソッドでiteratorに対しbindできる
* ObjectをいちいちArrayに変換して投げる必要がない
* ライブラリ内で落ちない
* 便利なメソッド追加
* https://github.com/suguru03/Neo-Async

```bash
$ npm install neo-async
```

## 作った経緯

* nullで本番サーバ死んだ
* PRが取り込まれない
* やりたいことができないことが多い
* 5月から更新無かった（作ってる間に少し更新された！）

## 速度比較

### 結果

* series
    * asyncより2.4倍速い
* parallel
    * asyncより2.8倍速い
* waterfall
    * ~~asyncより3.7倍速い~~
    * asyncより7.7倍速い (v0.2.5)

### 共通処理
```js
#!/usr/bin/env node --expose_gc
var _ = require('lodash');
var async = require('async');
var neo_async = require('neo-async');
var start = function() {
  return process.hrtime();
};
var getDiff = function(start) {
  var diff = process.hrtime(start);
  return diff[0] * 1e9 + diff[1];
};
var sample = 1000;
var time = {
  async: 0,
  neo_async: 0
};

```

* startとgetDiffは時間測定に使います。
* sample(tasks)数は全部共通で1000です。
* node --version v0.10.33

### series

```js
// seriesのタスク作ります
var tasks = _.map(_.times(sample), function(item) {
  return function(callback) {
    callback(null, item);
  };
});

var timer = start();
async.series(tasks, function(err, res1) {
   time.async = getDiff(timer);
   
   global.gc();
   timer = start();
    neo_async.series(tasks, function(err, res2) {
      time.neo_async = getDiff(timer);

      // res1とres2が完全に一致してるかチェックしてます
      var check = _.every(res1, function(item, index) {
        return res2[index] === item;
      });
      console.log('check', check);
      console.log('**** time ****');
      console.log(time);
      console.log(time.async / time.neo_async);
    });
});
```

* async, neo_asyncの順
    * { async: 2632607, neo_async: 1097360 }
    * 2.4倍
* neo_sync, asyncの順
    * { async: 3749187, neo_async: 1615040 }
    * 3.4倍

### parallel

```js
var tasks = _.map(_.times(sample), function(item) {
  return function(callback) {
    callback(null, item);
  };
});

var timer = start();
neo_async.parallel(tasks, function(err, res1) {
   time.neo_async = getDiff(timer);

   global.gc();
   timer = start();
    async.parallel(tasks, function(err, res2) {
      time.async = getDiff(timer);

      var check = _.every(res1, function(item, index) {
        return res2[index] === item;
      });
      console.log('check', check);
      console.log('**** time ****');
      console.log(time);
      console.log(time.async / time.neo_async);
    });
});
```
* async, neo_asyncの順
    * { async: 3291565, neo_async: 1166516 }
    * 2.8倍
* neo_sync, asyncの順
    * { async: 3326372, neo_async: 1174852 }
    * 2.8倍

### waterfall

```js
// waterfall作るタスクです。
var tasks = (function createSimpleTasks(num) {
  var first = true;
  var tasks = _.transform(_.times(num), function(memo, num, key) {
    if (first) {
      first = false;
      memo[key] = function(done) {
        done(null, num);
      };
    } else {
      memo[key] = function(sum, done) {
        done(null, sum + num);
      };
    }
  });
  return tasks;
})(sample);

var timer = start();
async.waterfall(tasks, function(err, res1) {
  time.neo_async = getDiff(timer);

  global.gc();
  timer = start();
  async.waterfall(tasks, function(err, res2) {
    time.async = getDiff(timer);

    console.log('check', res1 === res2);
    console.log('**** time ****');
    console.log(time);
    console.log(time.async / time.neo_async);
  });
});
```
#### v0.1.0
* async, neo_asyncの順
    * { async: 11875267, neo_async: 3183565 }
    * 3.7倍
* neo_sync, asyncの順
    * { async: 11667079, neo_async: 2760822 }
    * 4.2倍

#### v0.2.5
* async, neo_asyncの順
	* { async: 10423769, neo_async: 1349466 }
	* 7.7倍
* neo_sync, asyncの順
	* { async: 10460708, neo_async: 1366448 }
	* 7.7倍

## 機能一覧

### Collections

* async.each [Series, Limit]
* async.map [Series, Limit]
* async.filter [Series, Limit]
* async.reject [Series, Limit]
* async.detect [Series, Limit]
* async.pick [Series, Limit]
* async.transform [Series, Limit]
* async.reduce
* async.reduceRight
* async.sortBy [Series, Limit]
* async.some [Series, Limit]
* async.every [Series, Limit]
* async.concat [Series, Limit]

### Control Flow

* async.series
* async.parallel [Limit]
* async.waterfall
* async.whilst
* async.doWhilst
* async.until
* async.doUntil
* async.forever
* async.seq
* async.applyEach [Series]
* async.queue
* async.priorityQueue
* async.cargo
* async.auto
* async.retry
* async.iterator
* async.nextTick
* async.setImmediate
* async.times [Series, Limit]

### Utils

* async.memoize
* async.unmemoize
* async.log
* async.dir
* async.noConflict

## 今後の予定

* プロジェクトで使う！
* フロント対応
* テストケースの追加
* 便利な機能追加
* 冗長なのでリファクタする

## 終わりに

最後まで読んでいただき有難うございました。
まだまだ未熟ですがより良いモノ作りができるよう頑張って行きたいです。