Почему я не могу просто вызвать Error
обратный вызов внутри catch и позволить процессу обрабатывать ошибку, как если бы она была в любой другой области?
Если я не сделаю console.log(err)
ничего, ничего не распечатывается, и я ничего не знаю о том, что произошло. Процесс просто заканчивается ...
Пример:
function do1() {
return new Promise(function(resolve, reject) {
throw new Error('do1');
setTimeout(resolve, 1000)
});
}
function do2() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
reject(new Error('do2'));
}, 1000)
});
}
do1().then(do2).catch(function(err) {
//console.log(err.stack); // This is the only way to see the stack
throw err; // This does nothing
});
Если обратные вызовы выполняются в основном потоке, почему их Error
проглатывает черная дыра?
javascript
asynchronous
promise
throw
es6-promise
demian85
источник
источник
.catch(…)
возвращается..catch((e) => { throw new Error() })
, напиши.catch((e) => { return Promise.reject(new Error()) })
или просто.catch((e) => Promise.reject(new Error()))
Ответы:
Как объясняли другие, «черная дыра» возникает из-за того, что бросание внутрь
.catch
продолжает цепочку с отклоненным обещанием, и у вас больше нет ловушек, что приводит к незавершенной цепочке, которая поглощает ошибки (плохо!)Добавьте еще одну уловку, чтобы увидеть, что происходит:
Уловка в середине цепочки полезна, когда вы хотите, чтобы цепочка продолжалась, несмотря на неудачный шаг, но повторный бросок полезен для продолжения сбоя после выполнения таких действий, как регистрация информации или шаги очистки, возможно, даже изменение того, какая ошибка брошен.
выходка
Чтобы ошибка отображалась в веб-консоли как ошибка, как вы изначально задумывали, я использую следующий трюк:
Даже номера строк сохраняются, поэтому ссылка в веб-консоли ведет меня прямо к файлу и строке, где произошла (исходная) ошибка.
Почему это работает
Любое исключение в функции, называемой обработчиком выполнения или отклонения обещания, автоматически преобразуется в отклонение обещания, которое вы должны вернуть. Об этом позаботится код обещания, который вызывает вашу функцию.
С другой стороны, функция, вызываемая setTimeout, всегда запускается из стабильного состояния JavaScript, т.е. запускается в новом цикле в цикле событий JavaScript. Исключения там ничем не улавливаются и попадают в веб-консоль. Поскольку
err
содержит всю информацию об ошибке, включая исходный стек, файл и номер строки, она по-прежнему отображается правильно.источник
function logErrors(e){console.error(e)}
тогда используйте это какdo1().then(do2).catch(logErrors)
. Ответ сам по себе отличный, кстати, +1window.onerror
обработчике событий.setTimeout
Это можно сделать, только выполнив фокус. В противном случаеwindow.onerror
никогда не услышите ничего об ошибках, произошедших в Promise.console.log
илиpostErrorToServer
, ты можешь просто делать то, что нужно. Нет причин, по которым любой код неwindow.onerror
может быть выделен в отдельную функцию и вызван из двух мест. Наверное, даже корочеsetTimeout
очереди.Важно понять здесь
Как
then
иcatch
функции возвращают новые объекты обещания.Либо бросок, либо явный отказ переместит текущее обещание в отклоненное состояние.
Поскольку
then
иcatch
возвращают новые объекты обещаний, их можно связывать в цепочку.Если вы выбрасываете или отклоняете внутри обработчика обещаний (
then
илиcatch
), оно будет обработано в следующем обработчике отклонения по пути цепочки.Как отметил jfriend00, что
then
иcatch
обработчики не выполняются синхронно. Когда проводник бросает, это немедленно заканчивается. Таким образом, стек будет размотан, и исключение будет потеряно. Вот почему генерирование исключения отклоняет текущее обещание.В вашем случае вы отвергаете внутри
do1
, бросаяError
объект. Теперь текущее обещание будет в отклоненном состоянии, и управление будет передано следующему обработчику, какthen
в нашем случае.Поскольку в
then
обработчике нет обработчика отклонения,do2
он не будет выполняться вообще. Вы можете подтвердить это, используяconsole.log
внутри него. Поскольку текущее обещание не имеет обработчика отклонения, оно также будет отклонено со значением отклонения из предыдущего обещания, и управление будет передано следующему обработчику, которым являетсяcatch
.Как
catch
и обработчик отклонения, когда вы делаете этоconsole.log(err.stack);
внутри него, вы можете увидеть трассировку стека ошибок. Теперь вы выбрасываетеError
из него объект, поэтому обещание, возвращаемое функциейcatch
, также будет в отклоненном состоянии.Поскольку вы не прикрепили обработчик отклонения к объекту
catch
, вы не можете наблюдать отклонение.Вы можете разделить цепочку и лучше понять это, например
Результат, который вы получите, будет примерно таким:
Внутри
catch
обработчика 1 вы получаетеpromise
отклоненное значение объекта.Таким же образом обещание, возвращаемое
catch
обработчиком 1, также отклоняется с той же ошибкой, с которойpromise
было отклонено, и мы наблюдаем это во второмcatch
обработчике.источник
.then()
обработчики являются асинхронными (стек разматывается перед их выполнением), поэтому исключения внутри них должны быть преобразованы в отклонения, иначе не было бы обработчиков исключений, которые их перехватили.Я пробовал
setTimeout()
описанный выше метод ...К сожалению, я обнаружил, что это невозможно проверить. Поскольку он вызывает асинхронную ошибку, вы не можете заключить его в
try/catch
оператор, потому чтоcatch
к моменту возникновения ошибки прослушивание будет прекращено.Я вернулся к использованию просто слушателя, который работал отлично и, поскольку именно так должен использоваться JavaScript, был хорошо протестирован.
источник
Согласно спецификации (см. 3.III.d) :
Это означает, что если вы создадите исключение в
then
функции, оно будет перехвачено, и ваше обещание будет отклонено.catch
здесь нет смысла, это просто ярлык для.then(null, function() {})
Я думаю, вы хотите регистрировать необработанные отклонения в своем коде. Большинство обещаний библиотек запускают
unhandledRejection
за это. Вот соответствующая суть с обсуждением этого.источник
unhandledRejection
ловушка предназначена для серверного JavaScript, на стороне клиента разные браузеры имеют разные решения. МЫ еще не стандартизировали это, но постепенно, но верно.Я знаю, что это немного поздно, но я наткнулся на эту ветку, и ни одно из решений не было легко реализовать для меня, поэтому я придумал свое:
Я добавил небольшую вспомогательную функцию, которая возвращает обещание, например:
Затем, если у меня есть определенное место в какой-либо цепочке обещаний, где я хочу выдать ошибку (и отклонить обещание), я просто возвращаюсь из приведенной выше функции с моей созданной ошибкой, например:
Таким образом, я контролирую выброс дополнительных ошибок из цепочки обещаний. Если вы хотите также обрабатывать «нормальные» ошибки обещаний, вы должны расширить свой улов, чтобы обрабатывать «самовыданные» ошибки отдельно.
Надеюсь, это поможет, это мой первый ответ на stackoverflow!
источник
Promise.reject(error)
вместоnew Promise(function (resolve, reject){ reject(error) })
(для чего в любом случае потребуется оператор return)Да, обещает ошибки проглатывания, и вы можете их отловить
.catch
, как более подробно описано в других ответах. Если вы находитесь в Node.js и хотите воспроизвести нормальноеthrow
поведение, выводить трассировку стека на консоль и выйти из процесса, вы можете сделатьисточник
unhandledRejection
событие