AngularJSの$httpサービスとHttpPromiseのメソッド・チェーン
AngularJSはいろいろ便利な半面、ちょっと扱いづらい──というか基礎知識が必要になる部分も少なくありません。まあフレームワークというのはそういうものです。
直近ハマったのは$http
サービスでREST APIに複数のリクエストをしたあとそのレスポンスを待機するというロジックです。
問題となるのは$http
やそれを抽象化した$resource
はいずれも非同期通信だけをサポートしているという点です。ようするに厳密な意味での「待機」は不可能ということです。処理効率の点ではこれはよいことなのですが、そうはいってもロジック上守るべき順序関係が存在するということはしばしばあります。
このためAngularJSのHttpPromise
オブジェクトが提供するコールバックAPIを使用します。備忘のためメモしておきます。
まず、単一のリクエストとそのレスポンスの待機であれば下記のようにするか:
$http(config).success(function(response) { // ここにレスポンスが(正常に)帰ってきた時のロジックを記述 // response.dataにレスポンス本文が格納されている });
あるいは下記のようにすればレスポンスが帰ったあとに行うべきロジックを記述できます:
$http(config).then(function(response) { // ここにレスポンスが(正常に)帰ってきた時のロジックを記述 // response.dataにレスポンス本文が格納されている });
これは公式のドキュメントにもしっかり載っていますので問題ないでしょう。しかし複数のリクエストとそのレスポンスの待機をするにはどうしたらよいのでしょうか。
あれこれ調べてみた結果見つけた解決策(たぶん)は、下記のようにHttpPromise#then(Function... callbacks)
メソッドをチェーンさせるというものです:
$http(config0).then(function(response0) { // ここに1つめのレスポンスが(正常に)帰ってきた時のロジックを記述 // response0.dataにレスポンス本文が格納されている return $http(config1); }).then(function(response1) { // ここに2つめのレスポンスが(正常に)帰ってきた時のロジックを記述 // response1.dataにレスポンス本文が格納されている // 1つめのレスポンスが(正常に)帰ってきており // それにともなうコールバック関数が実行されていることは保証されている });
「あれこれ調べて」とは言いつつもHttpPromise
の仕様をきちんと調べているわけでもないので、「たぶんこれが解決策だろう」という感じです(少なくとも狙いどおりには動いています)。
上記の例だとそれぞれのレスポンスの処理結果(2度めの$http
の呼び出しの結果ではなく、response0
に対する何らかの処理の結果)はエンクロージング・スコープの変数に格納することになるので、コードがスパゲティ化するという問題があります。1つめのコールバック関数の処理結果をエンクロージング・スコープを介さずに2つめのコールバック関数に渡せれば状況は改善するのですが、その方法はあるのかまだわかっていません。