web-dev-qa-db-ja.com

Angular複数の$ httpでの約束

複数の$http呼び出しを実行しようとしていますが、コードは次のようになります。

var data = ["data1","data2","data3"..."data10"];

for(var i=0;i<data.length;i++){
    $http.get("http://example.com/"+data[i]).success(function(data){
        console.log("success");
    }).error(function(){
        console.log("error");
    });
}

すべての$http呼び出しが成功したことを知ることをどのように約束できますか?いずれかが失敗した場合、何らかのアクションを実行します。

11
user1995781

$q.all()メソッドを使用することもできます。

だから、あなたのコードから:

var data = ["data1","data2","data3"..."data10"];

for(var i=0;i<data.length;i++){
    $http.get("http://example.com/"+data[i]).success(function(data){
        console.log("success");
    }).error(function(){
        console.log("error");
    });
}

あなたができること:

var promises = [];
data.forEach(function(d) {
  promises.Push($http.get('/example.com/' + d))
});
$q.all(promises).then(function(results){
  results.forEach(function(data,status,headers,config){
    console.log(data,status,headers,config);
  })
}),

上記は基本的にリクエスト全体を実行し、すべてが完了したときの動作を設定することを意味します。

前のコメントについて:

ステータスを使用すると、問題が発生したかどうかを知ることができます。また、必要に応じて、リクエストごとに異なる構成を設定することもできます(たとえば、タイムアウト)。

いずれかが失敗した場合、何らかのアクションを実行します。

ドキュメントから これも A +仕様に基づく:

$q.all(successCallback, errorCallback, notifyCallback);
12
diegoaguilar

最初のエラーを発生させたい場合は、次のようにforループを同期させる必要があります: 進行状況バーを更新するための角度同期httpループ

var data = ["data1", "data2", "data3", "data10"];
$scope.doneLoading = false;
var promise = $q.all(null);

angular.forEach(data, function(url){
  promise = promise.then(function(){
    return $http.get("http://example.com/" + data[i])
      .then(function (response) {
        $scope.data = response.data;
      })
      .catch(function (response) {
        $scope.error = response.status;
      });
  });
});

promise.then(function(){
  //This is run after all of your HTTP requests are done
  $scope.doneLoading = true;
});

非同期にしたい場合: バンドルする方法Angular $ http.get()呼び出し?

app.controller("AppCtrl", function ($scope, $http, $q) {
  var data = ["data1", "data2", "data3", "data10"];
  $q.all([
    for(var i = 0;i < data.length;i++) {
      $http.get("http://example.com/" + data[i])
        .then(function (response) {
          $scope.data= response.data;
        })
        .catch(function (response) {
          console.error('dataerror', response.status, response.data);
          break;
        })
        .finally(function () {
          console.log("finally finished data");
        });
    }
  ]).
  then(function (results) {
    /* your logic here */
  });
};

この記事もかなり良いです: http://chariotsolutions.com/blog/post/angularjs-corner-using-promises-q-handle-asynchronous-calls/

7
Enkode

受け入れられた答えは大丈夫ですが、それでも少し醜いです。送信したいものの配列があります。forループを使用する代わりに、Array.prototype.mapを使用してみませんか?

var data = ["data1","data2","data3"..."data10"];

for(var i=0;i<data.length;i++){
    $http.get("http://example.com/"+data[i]).success(function(data){
        console.log("success");
    }).error(function(){
        console.log("error");
    });
}

これは

var data = ['data1', 'data2', 'data3', ...., 'data10']
var promises = data.map(function(datum) {
  return $http.get('http://example.com/' + datum)
})
var taskCompletion = $q.all(promises)
// Usually, you would want to return taskCompletion at this point,
// but for sake of example

taskCompletion.then(function(responses) {
  responses.forEach(function(response) {
    console.log(response)
  })
})

これは高階関数を使用するため、forループを使用する必要はなく、見た目もはるかに簡単に見えます。それ以外の点では、投稿された他の例と同じように動作するため、これは純粋に美的な変更です。

successerrorの警告の一言--successerrorはコールバックに似ており、promiseがどのように機能するかわからないという警告です/正しく使用していません。 Promise thencatchはチェーンを作成し、これまでのチェーンをカプセル化した新しいPromiseを返します。これは非常に有益です。さらに、successerror$httpの呼び出しサイト以外の場所)を使用することは、Angular A +準拠のpromiseではなくHTTPpromise。

言い換えると、success/errorを使用しないようにしてください。理由はめったになく、副作用が発生するため、ほとんどの場合、コードの臭いを示します。


あなたのコメントに関して:

私は$ q.allで非常に簡単な実験を行いました。ただし、すべての要求が成功した場合にのみトリガーされます。それが失敗した場合、何も起こりません。

これは、allのコントラクトが、すべての約束が成功した場合はifを解決するか、少なくとも1つが失敗した場合は拒否するためです。

残念ながら、Angularの組み込みの$qサービスにはallしかありません。約束を拒否したい場合は、結果の約束が拒否されないようにする必要があります。これは、ほとんどの主要な約束ライブラリ(Bluebirdやkriskowalによる元のallSettledなど)に存在するQを使用する必要があります。 )。他の選択肢はあなた自身を転がすことです(しかし私はBluebirdを提案します)。

5
Dan Pantry