Учебник веб-разработки
Разделы учебника
На этой странице

X. Инструменты и проверки

Отладчик и профилировщик

Оглавление · Диагностика

Отладчик отвечает «какие значения и вызовы привели к этому состоянию». Профилировщик — «куда уходит время или память». Лог полезен для наблюдения за последовательностью событий; остановка на breakpoint меняет время выполнения и может скрыть гонку. Сначала воспроизведите симптом на минимальном наборе данных.

Ошибка значения

Сохраните во временный debug.mjs:

function total(prices) {
  return prices.reduce((sum, price) => sum + price, 0);
}
console.log(total([10, "20", 30]));

Запустите node debug.mjs: получится строка 102030. Запустите node --inspect-brk=127.0.0.1:9237 debug.mjs с собственным свободным портом, подключите Node debugger редактора либо Chrome через chrome://inspect. Поставьте breakpoint внутри reducer, продолжите выполнение и смотрите typeof sum, typeof price, Call Stack и Scope. Step over выполняет вызов, step into входит в него; продолжение идёт до следующей точки остановки. Inspector держите на loopback; после опыта завершите свой процесс.

Ошибка появилась до суммирования: вход содержит строку. Приведение as number[] не исправляет runtime-данные. Выберите контракт: только числа или явно разрешённые числовые строки. Проверьте вход на границе, затем добавьте проверку поведения. Не преобразуйте любой нечисловой текст в 0: это скрывает ошибку данных.

CPU-профиль без дополнительной зависимости

Во временный profile.mjs:

function checksum() {
  let value = 0;
  for (let i = 0; i < 20_000_000; i++) value = (value + i) % 1_000_003;
  return value;
}
console.log(checksum());

Из этого временного каталога:

node --cpu-prof --cpu-prof-name=lesson.cpuprofile profile.mjs

Получится число 1830 и файл профиля. Импортируйте его в Performance DevTools. Найдите checksum в Call Tree, сравните self time с total time: время собственного тела отличается от времени вместе с дочерними вызовами. CPU-профиль основан на выборках; короткая функция может не попасть в выборку. Результаты зависят от прогрева, компьютера и фоновой нагрузки. Повторяйте сравнение на одинаковом входе и отдельно измеряйте общее время.

Исходник схемы
flowchart LR
  Symptom[Симптом] --> Reproduce[Воспроизводимый вход]
  Reproduce --> Hypothesis[Гипотеза]
  Hypothesis --> Measure[Breakpoint или профиль]
  Measure --> Change[Минимальная правка]
  Change --> Compare[Поведение и повторное измерение]

CPU-профиль не объяснит ожидание ответа CMS: процесс в это время может почти не использовать CPU. Сопоставьте сетевой waterfall, длительности запросов и трассировку. Не оптимизируйте reducer, если основная задержка — последовательные сетевые обращения.

Браузер и React

Performance показывает scripting, layout и paint; React Profiler — commits и затраты компонентов. Изменение props может вызвать render, который ещё не означает дорогое изменение DOM. Сначала найдите дорогой сценарий, затем проверьте число вызовов, зависимости effects и расположение state. Добавление memo или useMemo без измерения усложняет код и может ничего не ускорить. Dev Strict Mode и production имеют разные условия; сравнение должно их учитывать. Production-сборки проекта выполняются в CI, локально используйте dev и маленькие изолированные примеры.

Для памяти сравнивайте heap snapshots после одинаковых действий и сборки мусора, ищите удерживающие ссылки: listeners, замыкания, коллекции. Рост RSS сам по себе не доказывает утечку JS-объектов. Heap snapshot может содержать значения данных; учебные профили собирайте с вымышленными входами и не коммитьте реальные снимки.

Приёмка: укажите исходный симптом, воспроизведение, наблюдение, причинную гипотезу и результат правки. Для ускорения покажите до/после с одинаковым входом, для ошибки — случай, который раньше давал неверный ответ. Нативные вычисления можно проверить отдельно; работа интерфейса debugger и браузерных профилей требует ручного опыта.

Источники: CLI Node.js 24, отладка Node, React Profiler.