読者です 読者をやめる 読者になる 読者になる

M12i.

学術書・マンガ・アニメ・映画の消費活動とプログラミングについて

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つめのコールバック関数に渡せれば状況は改善するのですが、その方法はあるのかまだわかっていません。