асинхронная функция в обещании выдает ошибку и не отклоняет

Если есть промис с асинхронной функцией и если в асинхронной функции происходит ошибка, то промис не ловит, а выдает ошибку и вылетает приложение, чего я не понимаю.

Очевидно, я хотел бы обработать ошибку. Знаете ли вы, почему обещание ведет себя так и как это можно обойти?

спасибо

// 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);
});


person Deli Sandor    schedule 09.02.2019    source источник


Ответы (1)


Ошибки, возникающие внутри конструктора Promise и возникающие асинхронно, должны быть явно try/catched, чтобы можно было вызвать reject, чтобы поток управления Promise мог быть передан catch Promise. Например:

// 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);
  });

В противном случае ни resolve, ни reject не будут вызываться, а ошибка была асинхронной, поэтому поток, в котором было создано обещание, уже завершился, поэтому интерпретатор не знает, что выданная ошибка должна отклонить это обещание без вашего явного указания.

Напротив, ошибки, возникающие синхронно внутри конструктора Promise, автоматически приведут к немедленному отклонению созданного промиса.

person CertainPerformance    schedule 09.02.2019
comment
so the thread the Promise was created on has already ended - Я думал, что в Javascript нет многопоточности. Можете ли вы немного подробнее объяснить, что происходит внутри Javascript, когда в асинхронном методе генерируется исключение? - person Rash; 11.07.2019
comment
Да, по большей части Javascript является однопоточным. Возможно, было бы разумнее сказать, что ошибка возникает на другой итерации цикла событий. Если во время асинхронного выполнения выдается ошибка, а стек синхронных вызовов начинается с .then, это приведет к отклонению промиса для этого .thenunhandledRejection, если он не обрабатывается должным образом). В противном случае, если в стеке синхронных вызовов нет .then (например, здесь вершина стека синхронных вызовов, когда выдается ошибка, является обратным вызовом setTimeout), это приведет к стандартной ошибке. - person CertainPerformance; 11.07.2019
comment
круто, так что давайте посмотрим, если я понимаю это. Когда запускается асинхронная функция (например, setTimeout), цикл событий не знает, что он выполняется внутри промиса. Таким образом, ошибка в асинхронном вызове приведет к сбою программы. Однако, если мы специально обработаем ошибку, вызвав отклонение промиса, он передаст управление обратно промису, тем самым спасая программу от сбоя. - person Rash; 11.07.2019
comment
Поскольку он не находится в основном потоке, он, вероятно, не приведет к сбою программы, он просто зарегистрирует, что произошла ошибка. Если вы вызываете reject или выполняете синхронный вызов внутри .then, ошибка передается для обработки Promise. Если ошибка не будет обработана промисом, вы получите необработанный отказ. Сообщение об ошибке для необработанного отклонения отличается, но в целом происходит то же самое - была выдана ошибка, которая не была обнаружена. - person CertainPerformance; 11.07.2019