js_gandalf
js_gandalf

Reputation: 891

Understanding Javascript Promises - Just want explanation

Here is what I'm trying to do. I need to do some pre-processing on a JSON object. In order to do so, I need to loop through each element, do a promise for a new person if there is no id for that person, and then update that element in the list.

Example:

participant:[{
    person:{
        firstName: 'john'
        lastName: 'Doe'
    },
    role: 'Plumber'
}, {
    person: '12345a9j09kf23f3'
    role: 'Window Washer'
}]

The first element doesn't have a person id, so I'm going to create a promise, create the person in the database and then update that element and replace 'John Doe' with a personId. The second element already has an id and doesn't need to go to the database to create a new person.

This code works as is. The problem is that I am trying to do a for loop and I need a synchrounous promise. I am in trouble. How can I use a loop and have a promise called or conditionally not handle a promise and the logic work synchronously?

Box.create(box)
.then(function(data) {
  _.forEach(participants, function (participant) {
      //This promise will be executed asynchronously, possible to make it synchronous with the for loop?
      if (typeof participant.person != 'undefined' && typeof participant.person.firstName != 'undefined') {
         Person.create(participant.person).then(function (data) {
            return Participant.create({}).then(function(data){
              newParticipants.push(data);
            })
          });
      } else {
        participants.push(participant);
      }
  });
  return Q(undefined);
}).then(function(){
 // more logic

Upvotes: 0

Views: 101

Answers (1)

Bergi
Bergi

Reputation: 664528

I need a synchrounous promise. I am in trouble

You cannot. Promises are inherently asynchronous. They're not a tool to make asynchronous tasks execute synchronously, they're an abstraction to work with asynchronous results smoothly.

What you can do is fire a task for each participant, to asynchronously create it in the database if it's not apparent there, and let them run in parallel. Then you easily take all the results (promise for them) and wait for all of them so that you get a promise for all results of all tasks - that's what Q.all does.

Instead of "looping" with foreach, you always should map to a new result - functional programming if you want. It would look like this:

Box.create(box).then(function(data) {
  var participants = data.participants; // or so?
  var promises = _.map(participants, function (participant) {
    if (typeof participant.person != 'undefined' && typeof participant.person.firstName != 'undefined') {
      return Person.create(participant.person)
             .then(Participant.create)
      // a promise for the new participant, created from the data that Person.create yielded
    } else {
      return Q(participant);
      // a (fulfilled) promise for the participant that we already have
    }
  });
  return Q.all(promises);
}).then(function(participants) {
  // more logic, now with all (old+new) participants
});

Upvotes: 1

Related Questions