0

I tried to reject a promise while iterating through some object properties, but the execution continues even after reject method was called ("passed here!!!" was logged in the console, even after the rejection).

function updateDocumentWithNewData(document, newData) {
 return new Promise(function(resolve, reject) {
    //some code...
    for (let key in newData) {
      if (newData.hasOwnProperty(key)) {
        //verifying if the document already has the property
        if (document.hasOwnProperty(key)) {
          reject({'message' : 'a property already exists...'});
        }
        //some code...
      }
    }
        
    //some more code...
    console.log("passed here!!!");
    resolve(document);
  }); 
}

I'm calling the method that returns this promise like this:

updateDocumentWithNewData(doc, data).then(function(result) {
  //Some code  
}).catch(function(err) {
  //Some code
});

The solution was to use a boolean variable, and call the "reject" method only after the loop finishes:

function updateDocumentWithNewData(document, newData) {
  return new Promise(function(resolve, reject) {
    //some code...
    let invalidUpdate = false;
    for (let key in newData) {
      if (newData.hasOwnProperty(key)) {
        //verifying if the document already has the property
        if (document.hasOwnProperty(key)) {
          invalidUpdate = true;
          break;
        }
        //some code...
      }
    }
    if (invalidUpdate) {
      reject({'message' : 'a property already exists...'});
    }
    
    //some more code...
    console.log("passed here!!!");
    resolve(document);
  }); 
}

I don't know if i'm missing something stupid, but I think that the rejection of the Promise should return imediatelly when "reject" is called and break the remaining code execution, so the first code should work. Is there something that I'm missing?

Fernando Ghisi
  • 419
  • 4
  • 8

1 Answers1

2

Calling reject won't stop the promise from executing, it'll just set the promise's state to rejected. It doesn't make the promise break code execution. (However, you won't have any problems with calling resolve later, as a Promise's state can only be changed from pending to rejected or fulfilled exactly once)

If you want to break code execution, you need to use return reject(reason) (Or return resolve(value)). Otherwise, the promise will run until the end of its code, and then any .then callbacks associated with the promise will be called. This is intended behavior. Another way to stop promise execution immediately is to throw an error, which will cause the promise to reject with that error.

So the way to make your original code work is:

function updateDocumentWithNewData(document, newData) {
 return new Promise(function(resolve, reject) {
    //some code...
    for (let key in newData) {
      if (newData.hasOwnProperty(key)) {
        //verifying if the document already has the property
        if (document.hasOwnProperty(key)) {
          return reject({'message' : 'a property already exists...'});
        }
        //some code...
      }
    }

    //some more code...
    console.log("passed here!!!");
    resolve(document);
  }); 
}
Pedro Castilho
  • 10,174
  • 2
  • 28
  • 39
  • Thanks, Pedro. Perfect explanation - now some other weird behaviors that I saw on my tests with Promises also makes sense! :) – Fernando Ghisi Apr 08 '17 at 18:50