49
43

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Posted at

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 関数に変更を加えずに要件を満たせます。

参考

49
43
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
49
43

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?