yourfavorite
yourfavorite

Reputation: 517

Nested promises and how to get around em

I am using a promise to get some JSON from a URL. The JSON that is returned includes a list of new URLs that return JSON. My current implementation is failing due to the nested promises.

I need to do the following:

  1. request parent JSON url
  2. request each of the child JSON urls
  3. After each child promise returns JSON, I need to do some stuff with the child's JSON and the parent JSON.

I am getting the following error.

Warning: a promise was created in a handler at main.development.js:661:61 but was not returned from it

Boiled down version of my code:

myPromise(url)
  .then(response => {
    // process the data into an array of items
   items.forEach(item => {
      myPromise(item.url)
        .then(response2 => {
          // Do a thing here with data from response and response2
        });
    });
  });

Upvotes: 0

Views: 70

Answers (2)

Igor Raush
Igor Raush

Reputation: 15240

You error is actually just a warning. It is there for good reason; a common mistake is doing something like this

myPromise(url)
    .then(response => {
        somethingElseAsync(response);        
    })
    .then(myCallback);

and expecting myCallback to be invoked after somethingElseAsync has finished work. As far as I can tell, this is not your case, since you are not collecting the results of your child promises.

To suppress the warning, you can follow Keith's answer. As a bonus, you can tack another promise onto your chain which will resolve when all child promises have resolved.

As an alternative to Promise.map, if you are okay with spawning all child tasks simultaneously, you can get away with Promise.all, like this:

myPromise(url).then(response => {
    return Promise.all(items.map(item => {
        return myPromise(item.url).then(response2 => {
            // handle response and response2, return some result
            return result;
        });
    }));
}).then(results => {
    //    ^^^ an array of results returned from child promise callbacks
}).catch(error => {
    // either the parent promise or one of the child promises has rejected
});

Upvotes: 1

Keith
Keith

Reputation: 24181

Here I've done your example, using Bluebird map.

I've also added the concurrency option, this is very handy.. Leaving out, will just work a bit like promise.all, and putting a value of 1, would be were you want to do all the promises in series..

myPromise(url)
  .then(response => {
    // process the data into an array of items
   return Promise.map(items, item => {
     return myPromise(item.url)
        .then(response2 => {
          // Do a thing here with data from response and response2
        });
    }, {concurrency:10});  //lets do a max of 10 promises at a time.
  });

Upvotes: 1

Related Questions