Почему я теряю трассировку стека при использовании async-await в Node.js? - PullRequest
2 голосов
/ 14 марта 2019

Когда я запускаю следующую программу

async function functionOne() {

  throw new Error('Error here prints the complete stack');

  await new Promise((resolve) => {
    setTimeout(() => { resolve(); }, 1000);
  });
}

async function functionTwo() {
  await functionOne();
}

async function functionThree() {
  await functionTwo();
}

functionThree()
  .catch((error) => {
    console.error(error);
  });

Я получаю следующий вывод, который печатает стек через различные вызванные функции

Error: Error here prints the complete stack
    at functionOne (/home/divyanshu/programming/errorHandlingAsyncAwait/index.js:3:9)
    at functionTwo (/home/divyanshu/programming/errorHandlingAsyncAwait/index.js:11:9)
    at functionThree (/home/divyanshu/programming/errorHandlingAsyncAwait/index.js:15:9)
    at Object.<anonymous> (/home/divyanshu/programming/errorHandlingAsyncAwait/index.js:18:1)
    at Module._compile (module.js:612:30)
    at Object.Module._extensions..js (module.js:623:10)
    at Module.load (module.js:531:32)
    at tryModuleLoad (module.js:494:12)
    at Function.Module._load (module.js:486:3)
    at Function.Module.runMain (module.js:653:10)

Однако, если после вызова await в следующей программе выдается ошибка

async function functionOne() {

  await new Promise((resolve) => {
    setTimeout(() => { resolve(); }, 1000);
  });

  throw new Error('Error here prints incomplete stack');

}

async function functionTwo() {
  await functionOne();
}

async function functionThree() {
  await functionTwo();
}

functionThree()
  .catch((error) => {
    console.error(error);
  });

Это вывод

Error: Error here prints incomplete stack
    at functionOne (/home/divyanshu/programming/errorHandlingAsyncAwait/index.js:7:9)
    at <anonymous>

Я бы хотел понять, почему трассировка стека теряется во втором случае, а не в первом.

1 Ответ

2 голосов
/ 14 марта 2019

Потому что в первом коде все, вплоть до 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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...