【问题标题】:Chaining promises from a foreach loop从 foreach 循环链接承诺
【发布时间】:2016-03-27 07:52:31
【问题描述】:

如何在 AngularJS 中使 foreach 循环同步

var articles = arg;

articles.forEach(function(data){
      var promises = [fetchImg(data), fetchUser(data)];

      $q.all(promises).then(function (res) {
           finalData.push(res[1]);
      });
});

return finalData;

我希望仅在 forEach 循环结束后返回 finalData 数组。有没有办法用承诺链接它?会先执行foreach循环,然后在循环结束后返回数组的东西?

【问题讨论】:

  • 您似乎已经知道$q.all。为什么不用它?

标签: javascript arrays angularjs


【解决方案1】:

从 foreach 循环链接承诺

Promises 通过返回 值(或 Promise)链接.then 方法中的处理函数。使用$q.all 合并多个承诺,$q.all 本身返回一个 chainable 承诺。

function fetchUsers(arg) {
    var articles = arg;

    var promises = articles.map(function(a){
        var subPromises = [fetchImg(a), fetchUser(a)];        
        return $q.all(subPromises).then(function (res) {
             //return for chaining
             return {img: res[0], user: res[1]};
        });
    });

    //consolidate promises    
    var finalPromise = $q.all(promises); 
    return finalPromise;
};

因为调用 Promise 的 .then 方法会返回一个新的派生 Promise,所以很容易创建一个 Promise 链。可以创建任意长度的链,并且由于可以使用另一个 Promise 来解决一个 Promise(这将进一步推迟其解决方案),因此可以在链中的任何点暂停/推迟对 Promise 的解决。@ 987654321@

返回的 Promise 将通过一组用户解决或将通过第一个错误解决拒绝。使用 promise 的 .then.catch 方法检索最终解决方案。

 fetchUsers(args)
     .then ( function onFulfilled(objArray) {
          $scope.users = objArray.map(x => x.user);
          return objArray;
     }).catch ( function onRejected(response) {
          console.log("ERROR: ", response);
          throw response
     })
 ;

$q.defer 反模式

使用$q.defer() 的问题在于它破坏了promise 链,丢失了错误信息,并且在错误处理不当时会造成内存泄漏。有关这方面的更多信息,请参阅AngularJS Is this a “Deferred Antipattern”?

【讨论】:

  • 我假设这行 var p = $q.all(promises).then(function (res) { 承诺实际上应该是 subPromises 或者我错过了什么?
【解决方案2】:

你可以像这样修改你的代码:

function fetArticles(arg) {
    var articles = arg;
    var promises = [], finalData = [];
    var deferred = $q.defer();

    articles.forEach(function(data) {
          var userPromise = fetchUser(data);
          userPromise.then(function (res) {
               finalData.push(res[1]);
          });

          promises.push(fetchImg(data));
          promises.push(userPrommise);
    });

    $q.all(promises).then(function() {
         deferred.resolve({finalData: finalData, foo: "bar"});
    });

    return deferred.promise;
}

现在,调用这个方法并注册一个最终回调:

fetArticles(arg).then(function(data) {
     console.log("finalData: ", data.finalData, data.foo === "bar");
});

【讨论】:

  • var promises = [fetchImg(data), fetchUser(data)];表示获取图片数据和用户数据后,应将其插入到文章数据中,res[1] 表示最终数据来自 fetchUser(data),即来自 promises array[1] 位置。
  • Is this a “Deferred Antipattern”?。如果任何服务器请求失败,所写的答案将挂起$q.defer
猜你喜欢
  • 2014-11-25
  • 2016-02-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-13
  • 1970-01-01
相关资源
最近更新 更多