Потому что в первом коде все, вплоть до Error
, находится на одном такте цикла событий.
Прежде чем асинхронный обратный вызов из setTimeout
сможет войти в стек вызовов (трассировка стека построена из него), стек вызовов должен быть пустым.
Таким образом, поскольку первый код выполняет все синхронно до вызова Error
, все эти вызовы находятся в стеке вызовов. Но при втором подходе Error
вызывается после await
вызова setTimeout
. Когда setTimeout
сделано. Цикл событий помещает обратный вызов обратно в стек, для этого стек вызовов должен быть пустым.
Так что теперь у вас нет functionTwo
& functionThree
в стеке вызовов, поэтому они не появляются.
T трассировка стека - это состояние стека при возникновении ошибки.
Вот грубая интерпретация того, что происходит со стеком в обоих кодах:
Первый код
1) functionThree is pushed into the stack
2) functionTwo is pushed into the stack
3) functionOne is pushed into the stack
4) Error is thrown
Второй код
1) functionThree is pushed into the stack
2) functionTwo is pushed into the stack
3) functionOne is pushed into the stack
4) awat ...setTimeout is called
5) All 3 functions return a Promise
6) The stack is empty
... setTimeout ends
Next tick of the event loop
1) setTimeout callback is called
2) Error is thrown
Я рекомендую посмотреть это видео, чтобы понять, как все это работает:
Какого черта цикл событий в любом случае от Филиппа Робертса
В новых версиях Node.js вы можете использовать флаг --async-stack-traces
, чтобы улучшить трассировку стека при работе с асинхронным кодом.
Вы можете прочитать об этом подробнее на https://v8.dev/blog/fast-async