Как я могу выбросить исключение в Javascript, но сохранить стек?

151

В Javascript предположим, что я хочу выполнить некоторую очистку, когда происходит исключение, но пусть исключение продолжает распространяться вверх по стеку, например:

try {
  enterAwesomeMode();
  doRiskyStuff(); // might throw an exception
} catch (e) {
  leaveAwesomeMode();
  throw e;
}
doMoreStuff();
leaveAwesomeMode();

Проблема с этим кодом заключается в том, что перехват и повторное выбрасывание исключения приводят к потере информации трассировки стека до этой точки, поэтому, если исключение впоследствии будет перехвачено снова, при повышении в стеке трассировка стека будет только уменьшена до -throw. Это отстой, потому что это означает, что он не содержит функцию, которая фактически вызвала исключение.

Как выясняется, try..finally имеет такое же поведение, по крайней мере, в Chrome (то есть проблема заключается не в повторном вызове, а в наличии какого-либо блока обработчика исключений).

Кто-нибудь знает способ перебросить исключение в Javascript, но сохранить трассировку стека, связанную с ним? В противном случае, как насчет предложений о других способах добавления обработчиков безопасной очистки исключений, а также захвата полных трасс стека при возникновении исключения?

Спасибо за любые указатели :)

Geoff
источник

Ответы:

78

Это ошибка в Chrome. Восстановление исключения должно сохранить трассировку вызова.

http://code.google.com/p/chromium/issues/detail?id=60240

Я не знаю ни одного обходного пути.

Я не вижу проблемы с наконец. Я вижу исключения, которые молча не появляются на консоли ошибок в некоторых случаях после finally, но это, похоже, исправлено в сборках разработки.

Гленн Мейнард
источник
5
Этот вопрос с тех пор был закрыт.
Захари Бернс
24

Свойство стека объекта Error создается одновременно с самим объектом Error, а не в той точке, в которой оно было выброшено. Они часто одинаковы из-за идиомы

   выбросить новую ошибку («сообщение»);

и если вы используете код так, как вы его написали, свойство стека не изменится, когда вы перезапустите ошибку.

Майк Стей
источник
5
Это не так (возможно, зависит от платформы). Движок js, который я сейчас использую (Rhino), сбрасывает стек в операторе throw, теряя исходный стек.
Тед
1
Возможно и так, но Rhino-1.7.7.2.jar это не меняет. Какую версию ты используешь?
Майк Останься