Почему стек вывода ошибки в асинхронном коде отличается от синхронного

Почему в асинхронном коде в ошибке не выводится полный стек вызовов?

Ответы
Аватар пользователя Ivan Gagarinov
Ivan Gagarinov
28 сентября 2022

Чтобы прояснить, давайте разберем на таком примере :

import fs from 'fs';

const func1 = () => {
  const func2 = () => {
    callUndefinedFunction();
  };
  fs.readFile('./directory', 'utf-8', func2);
};

func1();

Вывод ошибки будет таким:

file:///tmp/test1/index.js:5
    callUndefinedFunction();
    ^

ReferenceError: callUndefinedFunction is not defined
    at ReadFileContext.func2 [as callback] (file:///tmp/test1/index.js:5:5)
    at FSReqCallback.readFileAfterOpen [as oncomplete] (node:fs:314:13)

Стек ошибки показывает на функцию func2(), но в нём нет родительской функции func1() вот эта строка:

at ReadFileContext.func2 [as callback] (file:///tmp/test1/index.js:5:5)

Дальше стек ошибки указывает на место в библиотечном коде: node:fs:314:13 - это мы уже не смотрим.

Теперь рассмотрим такой пример, уже с синхронным кодом:

const func2 = () => {
  throw Error();
};

const func1 = () => {
  func2();
};

func1();

Тут просто одна функция вложена в другую. Стек ошибки этого кода будет таким:

file:///tmp/test1/index-1.js:3
    throw Error();
          ^

Error
    at func2 (file:///tmp/test1/index-1.js:3:11)
    at func1 (file:///tmp/test1/index-1.js:6:3)
    at file:///tmp/test1/index-1.js:9:1
    at ModuleJob.run (node:internal/modules/esm/module_job:198:25)
    at async Promise.all (index 0)
    at async ESMLoader.import (node:internal/modules/esm/loader:385:24)
    at async loadESM (node:internal/process/esm_loader:88:5)
    at async handleMainPromise (node:internal/modules/run_main:61:12)

В стеке уже указываются обе функции, первые две строки:

    at func2 (file:///tmp/test1/index-1.js:3:11)
    at func1 (file:///tmp/test1/index-1.js:6:3)

Дальше идут строки из внутреннего кода ноды. По этому выводу мы видим стек ошибки, где на верхнем уровне стека функция func2(), внутри которой и была ошибка, ниже идёт func1(), внутри которой была вызвана функция func2(). То есть в стеке обе наши функции. В первом же примере в стеке нет функции func1(), там сразу на первом уровне стека идёт ReadFileContext.func2 (это по сути и есть наша функция-колбек func2()). Метод fs.readFile() вызвался, создал новый стек и поместил в этот стек колбек. Именно поэтому в нём нет func1().

0 0
Добавьте ваш ответ

Рекомендуемые курсы

состояние
JSX
компоненты
производительность
26 часов
Посмотреть
классы
инкапсуляция
контекст
прототипы
15 часов
Посмотреть
шаблонизация
REST
мидлвары
тестирование
11 часов
Посмотреть