Help us understand the problem. What is going on with this article?

async.js を捨てて Promise を使おう!

More than 5 years have passed since last update.

async.js が嫌いな訳ではありません。今までお世話になっていました。

Node.js v0.12 から Promise が標準で使えるようになったので async.js の parallelseries で行っていたことを Promise で実現しよう!という趣旨です。

parallel (並列実行)

var count = 0;
function echo() {
  var cnt = count++;
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      console.log(cnt);
      resolve(cnt);
    }, Math.random() * 1000);
  });
}

var promises = [echo(), echo(), echo()];

Promise.all(promises).then(function (values) {
  // 成功時処理 (実行順に関わらず values は [0, 1, 2])
  console.log("Succeeded!", values);
}).catch(function (err) {
  // 例外処理
  console.error("Failed.", err);
});

シングルスレッドなので正確には並列ではありませんが、処理が終了したものから順に出力されるため、実行する毎に表示される数字の順番が変わります。

series (直列実行)

var count = 0;
function echo() {
  var cnt = count++;
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      console.log(cnt);
      resolve(cnt);
    }, Math.random() * 1000);
  });
}

var tasks = [echo, echo, echo];

tasks.reduce(function (a, b) {
  return a.then(b);
}, Promise.resolve(null)).then(function () {
  // 成功時処理
  console.log("Succeeded!");
}).catch(function (err) {
  // 例外処理
  console.error("Failed.", err);
});

こちらは、必ず 0, 1, 2 の順に処理が走ります。
前の処理が終わるまで次の関数を評価しない為です。

まとめ

Promise はインスタンスが生成された時点で渡された関数を評価するため、直列実行したい場合は関数でラップする必要があります。

Array#reduce メソッドを利用することで、複数の Promise を返す関数を纏めて 1 つの Promise に集約することが出来ます。
Array#reduce の第 2 引数に初期値として Promise を渡します。このように記述すると、 tasks 配列が空の場合でも正しく処理が進みます。

直列実行の際に値を配列で受け取りたい

tasks.reduce(function (a, b) {
  return a.then(function (values) {
    return b().then(function (value) {
      return Promise.resolve(values.concat([value]));
    });
  });
}, Promise.resolve([])).then(function (values) {
  // 成功時処理
  console.log("Succeeded!", values);
}).catch(function (err) {
  // 例外処理
  console.error("Failed.", err);
});

そんな需要もあるかと思い、書いておきます。
reduce の中が複雑になりますが、このように記述することで echo 関数に変更を加えずに要件を満たせます。

参考

cyberagent
サイバーエージェントは「21世紀を代表する会社を創る」をビジョンに掲げ、インターネットテレビ局「AbemaTV」の運営や国内トップシェアを誇るインターネット広告事業を展開しています。インターネット産業の変化に合わせ新規事業を生み出しながら事業拡大を続けています。
http://www.cyberagent.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away