Семантика Javascript try-catch (стек вызовов в nodejs repl) - PullRequest
3 голосов
/ 04 ноября 2019

Я немного новичок в javascript, но я хотел попытаться понять, как работает отслеживание стека в nodejs. Мне было немного лень смотреть исходный код, поэтому я просто обратился к справочному языку https://www.ecma -international.org / ecma-262 / 10.0 / index.html # sec-runtime-semantics-catchclauseevaluation и попытался увидеть, что работает. Итак, вот загадка: в ответе я получаю некоторые странные результаты при ловле и броске.

Когда я запускаю:

try { throw Error('foo'); } catch (e) { throw e; }

, я получаю в качестве вывода:

Error: foo

Но когда я запускаю:

try { throw Error('foo'); } catch (e) { console.log(e); throw e; }

Я получаю в качестве вывода:

Error: foo
at repl:1:13
at ContextifyScript.Script.runInThisContext (vm.js:50:33)
at REPLServer.defaultEval (repl.js:240:29)
at bound (domain.js:301:14)
at REPLServer.runBound [as eval] (domain.js:314:12)
at REPLServer.onLine (repl.js:468:10)
at emitOne (events.js:121:20)
at REPLServer.emit (events.js:211:7)
at REPLServer.Interface._onLine (readline.js:282:10)
at REPLServer.Interface._line (readline.js:631:8)
Error: foo
at repl:1:13
at ContextifyScript.Script.runInThisContext (vm.js:50:33)
at REPLServer.defaultEval (repl.js:240:29)
at bound (domain.js:301:14)
at REPLServer.runBound [as eval] (domain.js:314:12)
at REPLServer.onLine (repl.js:468:10)
at emitOne (events.js:121:20)
at REPLServer.emit (events.js:211:7)
at REPLServer.Interface._onLine (readline.js:282:10)
at REPLServer.Interface._line (readline.js:631:8)

Кажется, что при вызове console.log(e) объект ошибки отслеживает выполнение стек контекста (надеюсь, я правильно использую этот термин), но если он проходит до repl без context.log(e), он знает только о своем сообщении об ошибке.

Я пробовал разные перестановкиэтого, а также вложения в разные лексические контексты (функции и другой блок try-catch), и все они, кажется, дают это «забавное» поведение. Кроме того, при выполнении этих сценариев я всегда получаю ожидаемое сообщение об ошибке и трассировку стека, поэтому я склонен полагать, что реализация repl здесь ошибочна. Однако, прежде чем углубляться в источник, я хотел бы проверить некоторых экспертов, чтобы выяснить, есть ли какая-то веская причина для такого поведения, или это просто глупый угловой случай, который я придумал.

1 Ответ

0 голосов
/ 05 ноября 2019

Ну, я не знаю, кошерно ли отвечать на мой собственный вопрос, но я покопался в источнике nodejs и выяснил, в чем дело. Я отследил его до repl.js: line 404. Здесь есть звонок на script.runInThisContext. В этот момент строка throw new Error() «ускользает» от репла и заканчивается тем, что попадает на несколько строк ниже. Здесь есть проверка для process.domain, которая, по-видимому, успешно выполняется в repl, но не в контексте скрипта. Это тогда выдает ошибку домена, которая не делает много. Если вы перейдете на self._domain.on('error',..., то увидите, что все вещи по трассировке стека здесь прорабатываются.

Я фактически добавил строку self._domain.emit('error'... к источнику прямо перед вызовом process.domain.emit('error',..., а затемраспечатал для меня хорошую трассировку стека, так что я напишу парням в nodejs и посмотрим, что они хотели бы исправить. Может быть, есть очень веская причина не делать этого, я не стал вдаваться в подробности.

В этот момент мне вспоминается сцена из Ожог после чтения. Смотрите, если у вас сухое чувство юмора: https://www.youtube.com/watch?v=46h7oP9eiBk

...