Как я могу выбросить исключение в Javascript, но сохранить стек?
В Javascript предположим, что я хочу выполнить некоторую очистку, когда происходит исключение, но пусть исключение продолжает распространяться вверх по стеку, например:
try {
enterAwesomeMode();
doRiskyStuff(); // might throw an exception
} catch (e) {
leaveAwesomeMode();
throw e;
}
doMoreStuff();
leaveAwesomeMode();
Проблема с этим кодом заключается в том, что перехват и повторная выдача исключения приводят к потере информации трассировки стека до этой точки, поэтому, если исключение впоследствии будет перехвачено снова, при повышении в стеке трассировка стека будет только уменьшена до -throw. Это отстой, потому что это означает, что он не содержит функцию, которая фактически вызвала исключение.
Оказывается, что try..finally имеет такое же поведение, по крайней мере, в Chrome (то есть проблема заключается не в повторном вызове, а в наличии какого-либо блока обработчика исключений).
Кто-нибудь знает способ перебросить исключение в Javascript, но сохранить трассировку стека, связанную с ним? В противном случае, как насчет предложений о других способах добавления обработчиков безопасной для исключения исключений, а также захвата полных трасс стека при возникновении исключения?
Спасибо за любые указатели:)
4 ответа
Это ошибка в Chrome. Повторное исключение должно сохранить трассировку вызова.
http://code.google.com/p/chromium/issues/detail?id=60240
Я не знаю ни одного обходного пути.
Я не вижу проблемы с наконец. Я вижу исключения, которые молча не появляются на консоли ошибок в некоторых случаях после finally, но это, похоже, исправлено в сборках разработки.
Свойство стека объекта Error создается одновременно с самим объектом Error, а не в той точке, в которой оно было выброшено. Они часто одинаковы из-за идиомы
выбросить новую ошибку ("сообщение");
и если вы используете код так, как вы его написали, свойство стека не изменится, когда вы перезапустите ошибку.
Как уже упоминалось, стек - это снимок, созданный во время работы
new Error(...)
, поэтому вы не можете выбросить ошибку с тем же стеком.
Я использовал обходной путь:
console.error
стек перед бросанием:
console.error(err.stack);
throw err;
Он не идеален, но дает вам достаточно информации, пригодной для отладки, и набор исходной ошибки.
Не ловите его в первую очередь, просто используйте, наконец
try {
enterAwesomeMode();
doRiskyStuff(); // might throw an exception
doMoreStuff();
} finally {
leaveAwesomeMode();
}