2

If there is a promise with an asynchronous function in it and if in the asynchronous function an error happens the promise doesn't catch but throws an error and crashes the application, which I don't understand.

Obviously I would like to handle the error, do you know why does the promise behave like this and what would be a way around it?

thanks

// this promise will have an error since param is not defined,
// and the promise won't be caught
function randomPromise(param) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            param[0] = 11;
        }, 2000);
    });
}

randomPromise()
.then(() => {
    console.log('nothing');
})
.catch((e) => {
    console.log('with set timeout or any async function in the promise, the error caused by \'param[0] = 11;\' wont bring the control here into the catch block just throws an error and crashes the application');
    console.log(e);
});

// this promise will have an error since param is not defined
// but the promise will be caught
function randomPromiseGoesToCatchBlock(param) {
    return new Promise((resolve, reject) => {
        param[0] = 11;
    });
}

randomPromiseGoesToCatchBlock()
.then(() => {
    console.log('nothing');
})
.catch((e) => {
    console.log('without the setTimeout function or any async function the error caused by \'param[0] = 11;\' brings the control here into the catch block');
    console.log(e);
});
vsemozhebuty
  • 12,992
  • 1
  • 26
  • 26
Deli Sandor
  • 151
  • 1
  • 10

1 Answers1

4

Errors that are thrown inside a Promise constructor and that occur asynchronously need to be explicitly try/catched so that reject can be called, so that the Promise control flow can be transferred to the Promise's catch. For example:

// this promise will have an error since param is not defined, and the promise wont be catched
function randomPromise(param) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      try {
        param[0] = 11;
      } catch(e) {
        reject(e);
      }
    }, 2000);
  });
}

randomPromise()
  .catch((e) => {
    console.log(e.message);
  });

Otherwise, neither resolve nor reject will be called, and the error was asynchronous, so the thread the Promise was created on has already ended, so the interpreter doesn't know that the thrown error should reject that Promise without you explicitly telling it to.

In contrast, errors thrown synchronously inside a Promise constructor will automatically result in the constructed Promise rejecting immediately.

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • `so the thread the Promise was created on has already ended` - I thought Javascript does not have multi-threading. Can you explain a bit more what happens internally in Javascript when an exception is thrown in an asynchronous method? – Rash Jul 11 '19 at 01:21
  • 1
    Yes, for the most part, Javascript is single-threaded. Maybe it would make more sense to say that the error occurs on a different iteration of the event loop. If, during asynchronous execution, an error is thrown, and the synchronous call stack starts at a `.then`, it'll result in the Promise for that `.then` rejecting (and an `unhandledRejection` if not handled properly). Otherwise, if there's no `.then` in the synchronous call stack (eg, here, the top of synchronous call stack when the error is thrown is the `setTimeout` callback), it'll result in a standard error. – CertainPerformance Jul 11 '19 at 01:47
  • cool, so let's see if I understand this. When an asynchronous function runs (e.g. setTimeout), the event loop has no idea that it is running inside a Promise. So an error in asynchronous call will crash the program. However, if we specifically handle the error by calling the Promise's reject, it passes the control back to the promise, thus saving the program from crashing. – Rash Jul 11 '19 at 02:03
  • 2
    Since it's not on the main thread, it probably won't "crash" the program, it'll just log that there was an error. If you call `reject`, or throw synchronously inside a `.then`, the error gets passed for the Promise to handle. If the error goes unhandled by the Promise, you'll get an unhandled rejection. The error message for an unhandled rejection is different, but the same general sort of thing is going on - an error was thrown which wasn't caught. – CertainPerformance Jul 11 '19 at 02:07