javascriptpromisethrow

why promise has a weird precedence for errors in js?


I have the code below and I expect to first have hi in my console then the error and at the end why, but the result is: hi, then why and the last one is error, so I'm wondering, why is this happening?

code:

const test = new Promise((resolve, reject) => {
 console.log("hi");
 throw new Error("error");
})

test.finally(() => {
  console.log("why")
})

Solution

  • I expect to first have hi in my console then the error and at the end why

    That's what you'd get if you were handling the rejection of the promise, like this:

    const test = new Promise((resolve, reject) => {
        console.log("hi");
        throw new Error("error");
    });
    
    test
    .catch((error) => console.error(error))
    .finally(() => {
        console.log("why")
    });

    ...but your code isn't handling rejection, so the rejection isn't reported until the environment's unhandled rejection code kicks in, which isn't until after all the code explicitly handling the promise has been executed.

    As you've said in a comment, new Promise and the execution of the function you pass it are all synchronous, but the error thrown in that function isn't unhandled, it's handled by the Promise constructor and converted to a promise rejection (which, later, is unhandled).

    So the sequence is:

    1. Create a promise
    2. Output hi
    3. Reject the promise with the error
    4. Attach a finally handler to it
    5. Run any appropriate handlers attached to the promise (since it's settled), in this case your finally handler
      1. Output why
      2. Reject the promise created by finally
    6. Determine that the rejection is unhandled and report it