LoginSignup
23
25

More than 1 year has passed since last update.

言語によってちょっと違うFuture/Promiseをまとめてみた(2)

Last updated at Posted at 2014-12-06

続き

前回はJava5、Java8、Play1Java についてFuture周りの仕様と使い方をなぞりました。

Play2Java、RxJava あたりも見ていきたいのですが、少し気分を変えるために今回は JavaScript を見ていくことにします。

JavaScript(ECMAScript6)

参考記事

こちらの記事に知りたいことがほとんど全部書いてありました……

Promises/A+

Promises/A+ というJavaScript標準仕様がある。抜粋すると:

  • "Promise" とは then メソッドを持つオブジェクトまたは関数のこと
  • このような関数を "thenable" と呼ぶ
  • Promise は pending, fulfilled, rejected のいずれかの状態をとり、不変である
  • then は onFulfilled と onRejected の2つのコールバック関数をとり、いずれかがただ一度だけ呼ばれる。
  • then は 各コールバック関数の結果を値とする次の Promiseを返す

どうやって Promise を生成するのか?

仕様では具体的な生成の方法は定めておらず、APIによって少しずつやり方が異なるとのこと。

ECMAScript6でのコード例は以下のようになります。

var promise = new Promise(function(resolve, reject) {
  ... // 重い処理
  if (success) {
     resolve(result);
  } else {
     reject(error);
  }
});

promise.then(
  function(result) { ... }, // 正常終了時の処理
  function(error)  { ... }  // エラー発生時の処理
).then(
  function(error)  { ... }  // 正常系だけを書ける
).catch(
  function(error) { ... }   // "catch" でエラー処理だけを書ける
)

メインの重い処理は then が呼ばれるまで動かない(中でsetTimeout()して非同期で動くようになっているらしいが未確認)。

Java だとコールバック登録してからスレッド与えて起動、というイメージのAPIでしたが、JavsScript ではコールバック登録したら処理開始を許す、というイメージですね。

タイムアウト

以下のようにタイムアウトしたらrejectするPromiseを作るというアプローチ。ちょっと煩雑……

 function timeout(ms, promise) {
        return new Promise(function (resolve, reject) {
            promise.then(resolve);
            setTimeout(function () {
                reject(new Error('Timeout after '+ms+' ms')); // (A)
            }, ms);
        });
    }

Promise の合成

  • すべての終了を待つのは Promise.all(promise_list)
  • 一つだけ待つのは Promise.race(promise_list)

jQuery.Deferred

こちらを参考にさせいもらいました

概要

  • jQuery.Deferred は jQuery独自の Promse を扱うためのオブジェクト。
  • Promise を生成したのち then を使う分には、Promises/A+ とほぼ同じ使い方ができる。
  • 元々は.then(A,B) ではなくて .done(A)(正常終了)、.fail(B)(エラー処理)という名前でチェーンしていた
  • .always() で最後に必ず呼びたい処理を書ける
  • Promise の生成の仕方が ECMAScript6 とちょっと違う

元々Deferred対応しているAjax関数などを使う

jQuery のAjax関数群は Promiseを返すようになっており、そのまま thanable 的に使える

$.get('...').then(function(result) {
  ...
})

自分で Promise を作る

Promise が内部で自分の親 Deferred を参照していて、その親のスコープにある重い処理本体までたどれるというつくりになっている

function myPromise() {
  var d = $.Deferred();
  setTimeout(function() {
    // 重い処理
    if (success) {
      d.resolve(result);
    } else {
      d.reject(error);
    }
  }, 1000);
  return d.promise();
}

並列実行

  • whenPromise を複数渡せば並列実行できる。"all"的なもの。一つでも失敗すると全体としてエラー扱い
  • "any" 的なものはなさそう
$.when(promise1, promise2, ...)
  .done(function(result1, result2, ...) { ... });

続く

少しずつ全体感が見えてきたように思います。引き続き Scala編に行ってみます。生きて帰りたい

23
25
1

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
23
25