続き
前回はJava5、Java8、Play1Java についてFuture周りの仕様と使い方をなぞりました。
Play2Java、RxJava あたりも見ていきたいのですが、少し気分を変えるために今回は JavaScript を見ていくことにします。
JavaScript(ECMAScript6)
参考記事
こちらの記事に知りたいことがほとんど全部書いてありました……
- JavaScript Promises - There and back again
- [JS]JavaScriptにおけるPromise/A+仕様を、チュートリアル形式で詳しく解説します
- あなたが読むべきJavaScript Promises
- ②ality – JavaScript and more
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 の動作が標準にそろえられたのは jQuery 1.8 から。 本家API - deferred.then()
- 元々は
.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();
}
並列実行
-
when
にPromise
を複数渡せば並列実行できる。"all"的なもの。一つでも失敗すると全体としてエラー扱い - "any" 的なものはなさそう
$.when(promise1, promise2, ...)
.done(function(result1, result2, ...) { ... });
続く
少しずつ全体感が見えてきたように思います。引き続き Scala編に行ってみます。生きて帰りたい