2013-04-30 5 views
17

約束APIで、2つの非同期要求を並行して送信し、結合結果を応答として解決する方法。今Promise API - 2つの非同期呼び出しの結果を組み合わせる

var get = function(id){ 
      var res1, res2; 
      var deferred = $q.defer(); 
      Db.get(id, "abc") 
       .then(function (d) { 
        //deferred.resolve(d)); 
        res1 = d; 
       }, function (e) { 
        //error 
       }); 

      Db.get(id, "def") 
       .then(function (d) { 
        //deferred.resolve(d)); 
        res2 = d; 
       }, function (e) { 
        //error 
       }); 

      //?????? how to return {res1:res1 , res2: res2} 

      return deferred.promise; 
     }; 

、私は私が示されているように結合された結果を取得する必要があります

get(123).then(function(d)){ 
// d= {res1: res1, res2: res2} 
}, 
... 

のように取得する()を呼び出すとき。 Angular promise APIでこれを行うにはどうすればいいですか?

答えて

36

@Mattによると、$q.allを使用する必要がありますが、使用法は正しくありません。 AngularJSは.done.failをサポートしておらず、複数の値の約束といったものがないという点で、まったく同じように機能しません。代わりに配列の約束を持っています。あなたがQフルを使ってこれを書いていた場合

我々は書きます。この場合

var get = function (id) { 
    return Q.all([Db.get(id, "abc"), Db.get(id, "def")]) 
     .spread(function (res1, res2) { 
      return {res1: res1, res2: res2}; 
     });//the error case is handled automatically 
}; 

.thenよう.spread行為を、それはの引数をかけて約束のために、アレイの結果を広げることを除いてonFulfilled機能。これをAngularJSのpromiseメソッドを使用するように変更するには、.spreadなしで行うだけです。これは、次の解決策につながる:

var get = function (id) { 
    return $q.all([Db.get(id, "abc"), Db.get(id, "def")]) 
     .then(function (res) { 
      return {res1: res[0], res2: res[1]}; 
     });//the error case is handled automatically 
}; 

これの美しさは、私たちが誤差伝播のすべての核心grityを処理し、フィルタとして機能し.thenので、部分的な結果を格納から解放されていることです。エラーハンドラを省略すると、自動的にエラーが伝播されます。つまり、いずれかの入力約束が拒否された場合、結果は拒否されます。両方の約束事が成功した場合、resはそれらの解決値の配列です。

+0

グレート答え1。また、わからないので、エラー処理の詳細を明確にしてくれてありがとう。しばらくお待ちいただいている場合は、http://stackoverflow.com/questions/16311803/chaining-2-asynchronous-calls-promise-api-to-run-seriallyを参考にして、then節がブロックされないように苦労してください。 – bsr

1

私は@ForbesLindesay答えに追加するものがあります。

私たちの場合、部分的な結果を望んでいました。要求が失敗した場合(たとえば、サーバーに問題がある場合、他の人が削除したものを要求した場合など)、有効な応答を収集し、エラー。

私は、約束事ごとに成功と失敗を処理し、$q.allによって収集される値を返す必要があることを知りました。ここで

は(... 'アイテム')我々のコードは、簡略化され、ジェネリックをした:我々はLodashを使用

var promiseList = _.map(itemList, function(item) 
{ 
    return DataService.getISubtems(item.id) 
     .then(
      function(response) 
      { 
       var subItems = response.data; 
       $log.info('Received sub-item list;' + subItems.length + ';items received'); 
       return subItems; 
      }, 
      function(reason) 
      { 
       $log.warn('Sub-item list not received for item;' + item.name + ';' + item.id); 
       $scope.errorList.push('Sub-item list not received for item "' + item.name + '"'); 
      } 
     ); 
}); 
$q.all(promiseList) 
    .then(function(itemArray) 
    { 
     // We get an array of arrays interleaved with undefined value when an error was raised. 
     // That's because error handling doesn't return anything, ie. returns undefined. 
     // We remove these undefined values then put all operations at the same level. 
     var allOperations = _(operationArray).reject(_.isUndefined).flatten().value(); 
     if ($scope.errorList.length > 0) 
     { 
      NotificationService.warning('Items Fetching', 'Errors while getting item list:\n' + 
       $scope.errorList.join('\n')); 
     } 
     $scope._onItemListReceived(allItems); 
    }); 

注意(_.map、_.flatten、_.reject、_.isUndefined )しかし私は使用法がかなり明確であると思う(これはこのライブラリの素晴らしい点だ!)。

+1

そこに文字列リテラル構文エラーがあるようです。 – Bergi

+0

修正しました。頭がおかしくなりました。これは、構文のハイライトやヒントなしでコードを手で編集するためのものです。大括弧であまりにも甘やかされている...:-) – PhiLho

+1

ありがとう:-)コードが読めるようになったので、私は 'scope.errorList'の使用について少し心配しています。この特殊なケースやチェーンの最後には機能するかもしれませんが、一般的なメソッドでは使用しないでください。むしろ最後のハンドラで '_.filter'できるエラーハンドラ(' undefined'sの代わりに)から専用の値を '返す '。 – Bergi

0

あなたはangular-q-spreadライブラリを使用して、ForbesLindesayの最初の例@と同じコードを使用することができます。

// The module needs $q-spread as a dependency: 
// angular.module('…', ['$q-spread']); 

var get = function (id) { 
    return $q.all([Db.get(id, "abc"), Db.get(id, "def")]) 
     .spread(function (res1, res2) { 
      return {res1: res1, res2: res2}; 
     }); 
}; 
関連する問題