最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Chaining promises from a foreach loop - Stack Overflow

programmeradmin2浏览0评论

How to make foreach loop synchronous in AngularJS

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;

I want finalData array to be returned only after the forEach loop gets over. Is there any way to chain it with promises? Something that will execute the foreach loop first and then return the array after the loop is over?

How to make foreach loop synchronous in AngularJS

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;

I want finalData array to be returned only after the forEach loop gets over. Is there any way to chain it with promises? Something that will execute the foreach loop first and then return the array after the loop is over?

Share Improve this question edited Jun 20, 2020 at 9:12 CommunityBot 11 silver badge asked Mar 27, 2016 at 7:52 foxtrot3009foxtrot3009 1492 silver badges7 bronze badges 1
  • You seem to know about $q.all already. Why don't you use it? – Bergi Commented Mar 27, 2016 at 21:38
Add a ment  | 

2 Answers 2

Reset to default 4

Chaining promises from a foreach loop

Promises are chained by returning values (or a promise) to the handler function in the .then method. Multiple promises are consolidated by using $q.all which itself returns a chainable promise.

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;
};

Because calling the .then method of a promise returns a new derived promise, it is easily possible to create a chain of promises. It is possible to create chains of any length and since a promise can be resolved with another promise (which will defer its resolution further), it is possible to pause/defer resolution of the promises at any point in the chain.1

The returned promise will either resolve fulfilled with an array of users or will resolve rejected with the first error. Final resolution is retrieved with the promise's .then and .catch methods.

 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
     })
 ;

The $q.defer Anti-pattern

The problem with using $q.defer() is that it breaks the promise chain, loses error information, and can create memory leaks when errors are not handled properly. For more information on that see, AngularJS Is this a “Deferred Antipattern”?.

You can modify your code like this:

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;
}

Now, call this method and register a final callback:

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

评论列表(0)

  1. 暂无评论