Getting different behaviour when using throw instead of reject in a promise

I’m getting an uncaught error in promise when using throw instead of reject. Why is this happening?

Also, why is promiseResponse not the value of the promise in rejected cases (thrown or using reject() ) but it is when it’s resolved? Just paste the below code in the console. Comment out reject and uncomment one of the other two cases to try them:

async function someFunction(url) {
  const promiseResponse = await requestData(url).catch(err => {
    console.error(err);
  });
    console.log('promiseResponse =', promiseResponse)
}

async function requestData(url) {
  return new Promise(function(resolve, reject) {
    const xhr = new XMLHttpRequest()
    xhr.onerror = function(event){
    //resolve('resolved')
    //throw new Error("Unable to make request")
    reject(new Error("Unable to make request"))
    }
xhr.open('GET', url)
xhr.send()
  });
}

someFunction('https://www.example.com/')

If you use throw it blocks execution and line reject(new Error("Unable to make request")) will never be executed.

In both cases promiseResponse will not have value, as only result of resolve is getting assigned to it and in both cases this function will not run.

Read my post again. I put the other cases in comments to make it easy for people to try them. As I mentioned, you have to comment out the other cases, they can’t all run at the same time.

Yes, I understood that.

**In case if you uncomment //resolve('resolved') before throwing, resolve() will fire and promiseResponse will have value and your promise will be resolved.

Another question, why would you resolve your promise .onerror, you shall not do this. Also throwing from Promise is really not good idea, the way it is now works great.

Each case is separate. If one is uncommented the other two should be. There’s no “resolve before throw”. Putting resolve in onerror is just for illustrative purposes.

It means that you can leave reject(new Error("Unable to make request")) uncommented, regardless, this line will never run.

If neither of resolve() and reject() invoked, Promise will always remain in “`pending” status.

Nevermind, snigo, you aren’t understanding me.

And that’s not true about throw, it does change the status to rejected. Try it yourself:

new Promise((resolve, reject) => {
throw new Error("An error occurred!");
}).catch(function(error) {console.error(error)})

In your example above, you are throwing directly inside the promise function. In your original example, you are throwing inside of a function that is inside of the promise function. There is nothing inside the promise function to catch the throw occurring in xhr.onerror. But you don’t need it, because you should be using reject anyway.

As to why promiseResponse is not getting the value you want, you are catching the error with the catch() you’ve tacked onto the end when you declare it. If you want to catch any errors then you should use try/catch instead.

1 Like

:slight_smile: My math teacher always kept telling me “Don’t compare chicken and sheep”.

Let’s just test:

const pending = new Promise((resolve, reject) => {
    setTimeout(() => {
      throw new Error("An error occurred!");
    }, 500);
}).then(() => console.log('LOGGED IF RESOLVED'))
  .catch(() => console.log('LOGGED IF REJECTED'));

If Promise is not resolved and not rejected, guess what’s the status?

1 Like

throw is only equivalent to reject in a function marked async (where you never use .then() and .catch() in the first place). Otherwise it evaluates the throw and executes it before it ever even gets to the .then() block.

Shorter: use the async keyword. It makes Promises much simpler and nicer to read. Would be nice if FCC taught it, but the curriculum predates ES7 where the keyword was introduced.