简体   繁体   中英

can't get recursive function with conditional promise to return final value

The issue I am having is that I need to get a total count of a collection of objects, which has the form of a tree where each object can also contain deeply nested objects. The collection of data I start with already has one nested layer available, but to find out if there is a third or more nested layers in an object, an API call has to be made with the nested object's id, which returns the next nested object if it exists. So, currently I have something like this:

function getCount(thread) {
  var deferred = $q.defer();
  var count = 0;
  function getComment(comment) {
    count++;

//if nested comments exist in data
    if (comment.fld.nested) {
      _.each(comment.fld.nested, function(x) {
        getComment(x);
      });
      deferred.resolve(count);

    } else if (comment.meta) {

//if not, load more from API with id
      return PostService.getComment(comment.meta.id).then(function(comment){
        if (comment.fld.nested) {
          _.each(comment.fld.nested, function(x) {
            return getComment(x);
          });
        }
        return count;
      });
    }
    return deferred.promise;
  }
  _.each(thread.fld.nested, function(x) {
    return getComment(x);
  });
return deferred.promise;
}


getCount(c).then(function(x) {
  console.log('final count:', x);
});

Right now, I can get the count for all objects nested to 2nd level deep, but anything loaded from the API promise is not included in the count when I call the getCount().then() function. How do I make this wait until all promises are resolved so I can get the final count returned?

Try removing the parameter "comment" from the API call then method:

From: function(comment){}

To: function(){}

As Jaromanda X mentioned in the comments, you're having getComment return an asynchronous promise, but you're not waiting for the results.

One aspect hindering you is that you're using deferred-style promises; if you were to use then , you'll have the benefit of being able to return a promise in a then handler, which will cause the outer promise to wait on the inner promise.

// foo won't resolve until Promise Two resolves.
var foo = getPromiseOne().then(function(valueOne) {
  return getPromiseTwo(valueOne);
});

You'll be waiting for a lot of promises in parallel, so I'm going to switch to Promise.all ( $q.all ) and Array.map ( _.map ) so it's clear what you're waiting for.

function getCount(thread) {
  var count = 0;
  function getComment(comment) {
    count++;

//if nested comments exist in data
    if (comment.fld.nested) {
      return $q.all(_.map(comment.fld.nested, function(x) {
        return getComment(x);
      }));
    } else if (comment.meta) {

//if not, load more from API with id
      return PostService.getComment(comment.meta.id).then(function(comment){
        if (comment.fld.nested) {
          return $q.all(_.map(comment.fld.nested, function(x) {
            return getComment(x);
          }));
        }
      });
    }
    return;  // Count matters, not return values, so returning undefined is fine.
  }

  // Wait for all nested promises to resolve, but ignore the array result
  // and return the count instead.
  return $q.all(_.map(thread.fld.nested, function(x) {
    return getComment(x);
  }).then(function() { return count; });
}

getCount(c).then(function(x) {
  console.log('final count:', x);
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM