世界中のJavaScriptについての情報を紹介するサイトです。
この記事は、 (JavaScript)ECMAScript6 promisesについてを理解するために読んだ方がよいと思われる記事やスライド等を紹介しています。
PromisesやDeferredといった言葉を非同期処理の話などで聞いた事があるかもしれませんが、 現在Promisesは次のECMAScriptの言語仕様として策定が進められています。
まだES6は策定段階ですが、既にPromisesについてはpolyfillとして利用できるライブラリ等もあり、また他のライブラリ内でもjQuery.Deferred()やAngularの$q等類似する実装が存在します。
そのため、Generators等に比べると今すぐ使えるし、既に使われている機能といえると思います。
ES6 PromisesはAPIとしてはそこまで数はなく、また類似する実装でも基本的にAPI名が異なるだけで挙動は同様なため(jQuery Defferdはちょっと異なりますが…)、ES6 Promisesについて学ぶことは今すぐ使える知識なので、この機会にPromisesについて調べてみるといいかもしれません。
紹介している記事は長いものも多いので、記事の簡単な概要とアウトラインをつけてあります。
特に読むべき順番などはないですが(上から順に読みやすい感じにしてはいます)、気になるワードが出てきたものから読んでみるのもいいですね。
JavaScript Promises: There and back again - HTML5 Rocks
http://www.html5rocks.com/en/tutorials/es6/promises/
Promisesについてよくまとまっていて、これを読めばひと通りの流れがわかるようになってる記事
load
,error
イベントで設定できる
complete
プロパティで判定して分岐する必要があるPromise
コンストラクタは2つのパラメータを持つ1つのコールバックを引数に取るvar promise = new Promise(function(resolve, reject) { … }
resolve
を呼び、それ以外は reject
を呼ぶthrow
しないで、reject
にErrorオブジェクトを渡して呼ぶthen
というコールバックを設定するメソッドを持っているpromise.then
で成功、失敗のコールバックを設定してあげる。then
というメソッドを持つオブジェクトを promise-like (or thenable)と呼ぶPromise.cast
が利用できるPromise.cast
を使うことでQのPromiseやjQueryのDeferredも扱えるvar jsPromise = Promise.cast($.ajax('/whatever.json'));
XMLHttpRequest
をラップしてpromiseオブジェクトを返すようにする例then
を使うことで非同期処理の後に別の処理を追加できるthen
のコールバックで値を変換することも出来る(return
で変換した値を返すだけ)then
の返り値(*1)に対してもthen
(next-then
)で処理を追加することができる。then
に設定されたコールバックは*1の値がsettles (succeeds/fails)になった時に呼ばれるthen
はsuccessとfailureのコールバックを指定できるがエラーについてのコールバックだけを書きたい場合
catch(function(response){ })
と書くことができるcatch
は then(undefined, func)
のシンタックスシュガーthen
/catch
で捉えることができるtry-catch
を使った方法を使う.catch()
のchainを書くだけとシンプルpromise.then
を使った非同期処理promise.then
の非同期処理しても上手く回らないケース
array.reduce
を使ってmutableな変数を使わないように逐次実行Promise.all
を使ってpromiseオブジェクトの配列をまとめて処理するJavaScript Promises - Thinking Sync in an Async World // Speaker Deck
https://speakerdeck.com/kerrick/javascript-promises-thinking-sync-in-an-async-world
▶ JavaScript Promises: Thinking Sync in an Async World - YouTube
Promisesにおけるデータの流れについてよくまとまっているスライド。
promiseの各メソッドについても紹介されているので全体像をさっとみるのに適している。
Pending
,Fulfilled
, Rejected
の3つPending
-(Value)-> Fulfilled
Pending
-(Reason)-> Rejected
Promise.prototype.then
Promise.prototype.catch
- promise.then(null, onFailure)
と同義Promise.cast
- オブジェクトをpromiseにするPromise.all
- 全てのpromiseが resolve
された時に次へ行くPrmises.race
- ひとつでもpromiseが resolve
された時に次へ行くnew Promise(function(resolve, reject){/* work */});
Promise.resolve
Promise.reject
then
の中での this
と bind
.catch
と console.error
を bindするw3ctag/promises-guide
https://github.com/w3ctag/promises-guide
Promisesはいろいろなライブラリで試されてきた概念で、それを元にPromises/A+というコミュニティベースな仕様が立ち上げられた。(Promises/A)
この仕様に対して多くのライブラリが適合するようになり、そして今Promisesは次のECMAScript仕様にも含まれるようになった。
PromisesはWeb Platformにおける非同期処理の一つのパラダイムであり、Streams APIなど他の仕様でも使われつつある。
このドキュメントはどのようにしてPromisesの仕様が作られたか、またPromisesをどのように使うかについて書かれている。
promise
を返す
promise
は 値を fulfilled
するか、又は理由と共に rejected
するonsuccess
/onerror
のようなイベントかコールバックで表現されていた.then(onReady, onFailure)
で既に状態を満たしている場合でも onReady
を呼ぶことが出来るthrow
すべきでないonRejected
には Error
型の値を渡すべきであるonRejected
は例外的な場合に使うべきであるonFulfilled
, onRejected
に渡す値で分けるべきpromises
を引数に受ける関数は Promise.cast
すべきである。Promise Anti-patterns
http://taoofcode.net/promise-anti-patterns/
Promisesのアンチパターンについて書かれている記事。
アンチパターンとそれを改善したパターンについて書かれているので、実際に書いてみて疑問に思ったりするパターンについてまとまっている。
then
の返り値はそれぞれ新しいpromiseを返すために起きるエラーハンドリングのミス
catch
できないthen
の返り値を返すようにするとcatch
できる http://www.es6fiddle.net/hs08nnaq/Promise.all
は array.reduce
を使って処理できるようにするthen()
の第二引数(onRejected
)でもエラーハンドリングはできるがonFulfilled
内でエラーが起きた場合に問題が起きるPromise nuggets
http://promise-nuggets.github.io/
Promisesとコールバックを使った実装の比較やPromisesのパターンについて書かれているチュートリアルサイト。
(途中で出てくるfs.readFileAsync(file)
はBluebirdのPromise.promisifyAllを使ったpromiseを返すバージョンの事)
Why I am switching to promises
http://spion.github.io/posts/why-i-am-switching-to-promises.html
Promise nuggetsの著者によって書かれたPromiseの利点についての記事。
throw-safeなエラーハンドリング、パフォーマンスとメモリ消費、promise.nodeifyを使ったコールバックスタイルとの互換性、Promiseの書き方やユースケース等について書かれている。
PromisesはChrome/Opera/Firefox等、一部ブラウザでしか実装されていませんが、 ECMAScript Language Specificationに基づく実装や、Promises/A+の実装ライブラリ等があります。 (どちらも基本的に挙動はほぼ同じで、API名が異なる部分がある程度です)
また、Advancedとなっているものは、基本的な実装は同じですがよくあるパターン等を拡張したメソッド等が実装されています。
またどちらのライブラリもAPIドキュメントが充実しているので、このライブラリを直接使わない場合でも見ておくといいかもしれません。
Promisesはコールバックの深いネストを減らせるという見た目的な問題だけではなく、 非同期処理の複雑なエラーハンドリングを分かりやすく書くことが出来る点等もメリットだと思います。
非同期のタイミングで値が入った時にどうするか?という事を書いた器(promiseオブジェクト)をやりとりすることで、 コールバックをネストした時に比べてあちこちに点々とする値ではなく、promiseオブジェクトという器に対して処理を集中して書けることが特徴だと思います。
そのため、器であるpromiseオブジェクトに対して何度もデータを入れるような”Event”や”Stream”と言った動作にはPromisesは不向きであるかもしれません。 必ずしも全てがPromisesで賄えるわけではないため、ひとつの手段として知っておくことが大切と言えると思います。
最後に、この記事は あなたが読むべきPromises by azu · Pull Request #17 · azu/jser.info で議論(という名のほぼ独り言)を元に書かれました。
このissueにはこの記事で紹介してない実装しながら学ぶ系の記事やモナドネタなども候補に出してましたが、今回は入れてないので興味がある人はそちらも見るといいかもしれません。
また、他にも読まれるべきだと思うものがある場合は、あなたが読むべきPromises by azu · Pull Request #17 · azu/jser.infoにコメント等しておけば更新されるかもしれません。
この記事/紹介してる記事がPromisesの理解の助けになればと思います。