javascriptnode.jsasynchronouspromisebluebird

How to get last process of async forEach?


I might be messing up things in the async hell I am currently in and would gladly take any help after debugging for half a day now.

The task is to asynchronously update a bunch of entities in the database. It is:

  1. Gets a list of entities of type Foo
  2. for each of these elements update it in the database
  3. SELECT entities of type Bar with corresponding conditions and update them accordingly
  4. After all updates return an array of objects of the form [{entity: 'Foo || Bar', id: foo.id || bar.id}]

What I currently have is the following (with Bluebird Promise.map):

exports.updateFooAndBars = function (req, res) {
  var arrayOfFoos = req.body;
  var projectId = req.params.projectId;
  var result = [];
  Promise.map(arrayOfFoos, function(foo, index){
    var fooId = foo.id;
    fooLib.update(foo, fooId)
    .then(function (updatedFoo){
      return barLib.update(foo, projectId);
    });
  })
  .then(function(result) {
    // handles PUT responses
    updated(res, result);
  })
  .catch(function(err) {
      .....
  )};

This of course does not work since the last .then-block is invoked before the others are done.

But I can't find out where and how I can jump in to process the response to the client exactly after every update has been finished? The index I am getting in Promise.map(arrayOfFoos, function(foo, index) is totally messing up during the processing such that I seem to not be able to rely on it for sending the response when index is equal to arrayOfFoos.length.

And since there might be quite plenty of entities which will be updated in this process, I do not want to this synchronously as far as I can avoid that to not block the backend during the process.

Thank you in advance!


Best regards,

Vegaaaa


Solution

  • You're not returning the Promise chain created by fooLib.update(). Your Promise.map() is iterating through all the items in the array, invoking the callback and continuing to the .then() on your Promise.map() immediately instead of waiting for all of the Promise chains created from each of the fooLib.update() calls.

    When working with Promises, if there is any internal Promise created, you need to return each of those to ensure the Promise chain is fully awaited for all asynchronous work, if that is something your code requires.

    Promise.map(arrayOfFoos, function(foo, index){
      var fooId = foo.id;
      return fooLib.update(foo, fooId)
        .then(function (updatedFoo){
          return barLib.update(foo, projectId);
        });
      })