Отладчик
Стабильность: 2 — Стабильный
Node.js включает в себя утилиту отладки командной строки. Клиент отладчика Node.js не является полнофункциональным отладчиком, но позволяет выполнять пошаговую отладку и проверку.
Отладчик поддерживает два режима работы: интерактивный режим и неинтерактивный режим зондирования.
Интерактивный режим
$ node inspect [--port=<port>] [<node-option> ...] [<script> [<script-args>] | <host>:<port> | -p <pid>] consolecopy
Чтобы использовать его, запустите Node.js с аргументом inspect, за которым укажите путь к отлаживаемому скрипту.
$ node inspect myscript.js
< Debugger listening on ws://127.0.0.1:9229/621111f9-ffcb-4e82-b718-48a145fa5db8
< For help, see: https://nodejs.org/learn/getting-started/debugging
<
connecting to 127.0.0.1:9229 ... ok
< Debugger attached.
<
ok
Break on start in myscript.js:2
1 // myscript.js
> 2 global.x = 5;
3 setTimeout(() => {
4 debugger;
debug>
consolecopy
Отладчик автоматически останавливается на первой исполняемой строке. Чтобы вместо этого выполнить код до первой точки останова (задаваемой оператором debugger), задайте для переменной окружения NODE_INSPECT_RESUME_ON_START значение 1.
$ cat myscript.js
// myscript.js
global.x = 5;
setTimeout(() => {
debugger;
console.log('world');
}, 1000);
console.log('hello');
$ NODE_INSPECT_RESUME_ON_START=1 node inspect myscript.js
< Debugger listening on ws://127.0.0.1:9229/f1ed133e-7876-495b-83ae-c32c6fc319c2
< For help, see: https://nodejs.org/learn/getting-started/debugging
<
connecting to 127.0.0.1:9229 ... ok
< Debugger attached.
<
< hello
<
break in myscript.js:4
2 global.x = 5;
3 setTimeout(() => {
> 4 debugger;
5 console.log('world');
6 }, 1000);
debug> next
break in myscript.js:5
3 setTimeout(() => {
4 debugger;
> 5 console.log('world');
6 }, 1000);
7 console.log('hello');
debug> repl
Press Ctrl+C to leave debug repl
> x
5
> 2 + 2
4
debug> next
< world
<
break in myscript.js:6
4 debugger;
5 console.log('world');
> 6 }, 1000);
7 console.log('hello');
8
debug> .exit
$
consolecopy
Команда repl позволяет удалённо выполнять код. Команда next переходит к следующей строке. Введите help, чтобы увидеть список остальных доступных команд.
Нажатие enter без ввода команды повторяет предыдущую команду отладчика.
Наблюдение
Во время отладки можно наблюдать за значениями выражений и переменных. При каждой точке останова каждое выражение из списка наблюдения вычисляется в текущем контексте и отображается непосредственно перед листингом исходного кода в точке останова.
Чтобы начать наблюдение за выражением, введите watch('my_expression'). Команда watchers выводит активные наблюдения. Чтобы удалить наблюдение, введите unwatch('my_expression').
Справочник по командам
Пошаговое выполнение
-
cont,c: Продолжить выполнение -
next,n: Перейти к следующей строке -
step,s: Войти в функцию -
out,o: Выйти из функции -
pause: Приостановить выполнение кода (как кнопка паузы в инструментах разработчика)
Точки останова
-
setBreakpoint(),sb(): Установить точку останова на текущей строке -
setBreakpoint(line),sb(line): Установить точку останова на указанной строке -
setBreakpoint('fn()'),sb(...): Установить точку останова на первом операторе в теле функции -
setBreakpoint('script.js', 1),sb(...): Установить точку останова на первой строкеscript.js -
setBreakpoint('script.js', 1, 'num < 4'),sb(...): Установить условную точку останова на первой строкеscript.js, которая срабатывает, только если выражениеnum < 4принимает значениеtrue -
clearBreakpoint('script.js', 1),cb(...): Удалить точку останова вscript.jsна строке 1
Также можно установить точку останова в файле (модуле), который ещё не загружен:
$ node inspect main.js
< Debugger listening on ws://127.0.0.1:9229/48a5b28a-550c-471b-b5e1-d13dd7165df9
< For help, see: https://nodejs.org/learn/getting-started/debugging
<
connecting to 127.0.0.1:9229 ... ok
< Debugger attached.
<
Break on start in main.js:1
> 1 const mod = require('./mod.js');
2 mod.hello();
3 mod.hello();
debug> setBreakpoint('mod.js', 22)
Warning: script 'mod.js' was not loaded yet.
debug> c
break in mod.js:22
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
21
>22 exports.hello = function() {
23 return 'hello from module';
24 };
debug>
consolecopy
Также можно установить условную точку останова, которая срабатывает, только если заданное выражение принимает значение true:
$ node inspect main.js
< Debugger listening on ws://127.0.0.1:9229/ce24daa8-3816-44d4-b8ab-8273c8a66d35
< For help, see: https://nodejs.org/learn/getting-started/debugging
<
connecting to 127.0.0.1:9229 ... ok
< Debugger attached.
Break on start in main.js:7
5 }
6
> 7 addOne(10);
8 addOne(-1);
9
debug> setBreakpoint('main.js', 4, 'num < 0')
1 'use strict';
2
3 function addOne(num) {
> 4 return num + 1;
5 }
6
7 addOne(10);
8 addOne(-1);
9
debug> cont
break in main.js:4
2
3 function addOne(num) {
> 4 return num + 1;
5 }
6
debug> exec('num')
-1
debug>
consolecopyИнформация
-
backtrace,bt: Вывести стек вызовов текущего кадра выполнения -
list(5): Вывести исходный код скриптов с контекстом в 5 строк (по 5 строк до и после) -
watch(expr): Добавить выражение в список наблюдения -
unwatch(expr): Удалить выражение из списка наблюдения -
unwatch(index): Удалить выражение с указанным индексом из списка наблюдения -
watchers: Вывести все наблюдения и их значения (автоматически выводятся при каждой точке останова) -
repl: Открыть REPL отладчика для выполнения выражений в контексте отлаживаемого скрипта -
exec expr,p expr: Выполнить выражение в контексте отлаживаемого скрипта и вывести его значение -
profile: Начать сеанс профилирования ЦП -
profileEnd: Остановить текущий сеанс профилирования ЦП -
profiles: Вывести список всех завершённых сеансов профилирования ЦП -
profiles[n].save(filepath = 'node.cpuprofile'): Сохранить сеанс профилирования ЦП на диск в формате JSON -
takeHeapSnapshot(filepath = 'node.heapsnapshot'): Создать снимок кучи и сохранить его на диск в формате JSON
Управление выполнением
-
run: Запустить скрипт (запускается автоматически при старте отладчика) -
restart: Перезапустить скрипт -
kill: Завершить скрипт
Прочее
-
scripts: Вывести список всех загруженных скриптов -
version: Показать версию V8
Режим зондирования
Стабильность: 1 — Экспериментальный
node inspect поддерживает неинтерактивный режим зондирования для проверки значений во время выполнения приложения с помощью флага --probe.
В настоящее время режим зондирования поддерживает только запуск нового процесса из скрипта точки входа, указанного в командной строке.
Режим зондирования устанавливает одну или несколько точек останова в исходном коде, вычисляет заданные выражения при каждом достижении точки останова и по завершении сеанса (при нормальном завершении, ошибке или истечении времени ожидания) выводит итоговый отчёт со всеми вычисленными выражениями. Это позволяет разработчикам выполнять отладку в стиле printf, не изменяя код приложения и не очищая его после этого. Также поддерживается структурированный вывод JSON для использования инструментами.
$ node inspect --probe <file>:<line>[:<col>] --expr <expr>
[--probe <file>:<line>[:<col>] --expr <expr> ...]
[--json] [--preview] [--timeout=<ms>] [--port=<port>]
[--] [<node-option> ...] <script> [<script-args> ...]
consolecopy
-
--probe <file>:<line>[:<col>]: Местоположение зонда в исходном коде. При достижении этого места выполняются указанные выражения, а их результаты выводятся в отчёте.<file>соответствует окончанию URL скрипта, который нужно проверить. Номера<line>и<col>отсчитываются от 1. Если<col>не задан, зонд привязывается к первой исполняемой колонке в строке. -
--expr <expr>: Выражение JavaScript, которое нужно вычислять при каждом достижении места, заданного предшествующим--probe. Оно должно непосредственно следовать за соответствующим ему--probe. -
--timeout=<ms>: Глобальный срок выполнения всего сеанса зондирования по часам. Значение по умолчанию —30000. Это можно использовать для зондирования долго работающего приложения, которое можно завершить извне. -
--json: Если указан, вместо текстового отчёта по умолчанию выводится структурированный отчёт JSON. -
--preview: Если указан, для непримитивных значений включаются предварительные данные свойств CDP для JSON-значений зонда, подобных объектам. -
--port=<port>: Задаёт локальный порт инспектора, на котором будет ожидать подключения сеанс зондирования. По умолчанию используется0, запрашивающий случайный порт. -
--необязателен, если только дочернему процессу не требуются собственные флаги Node.js.
Дополнительные правила для аргументов --probe и --expr:
-
--probe <file>:<line>[:<col>]и--expr <expr>должны использоваться строго парами. За каждым--probeдолжен непосредственно следовать ровно один--expr. -
--timeout,--json,--previewи--portявляются глобальными параметрами зондирования для всего сеанса. Они могут располагаться до пар зондов или между ними, но не между--probeи соответствующим ему--expr. - Если дочернему скрипту нужно передать дополнительные аргументы запуска Node.js, необходимо использовать
--, чтобы отделить параметры зондирования от параметров Node.js для дочернего скрипта.
Пример:
$ node inspect --probe app.js:10 --expr "user"
--probe src/utils.js:5:15 --expr "config.options"
--json --preview -- --no-warnings app.js --arg-for-app=foo
consolecopyФормат вывода зондирования
По завершении сеанса зондирования процесс зондирования выводит итоговый отчёт обо всех срабатываниях зонда и результатах.
Рассмотрим следующий скрипт:
// cli.js
let maxRSS = 0;
for (let i = 0; i < 2; i++) {
const { rss } = process.memoryUsage();
maxRSS = Math.max(maxRSS, rss);
}
jscopy
По умолчанию, без --json, вывод печатается в удобном для чтения формате:
$ node inspect --probe cli.js:5 --expr 'rss' cli.js Hit 1 at file:///path/to/cli.js:5:3 rss = 54935552 Hit 2 at file:///path/to/cli.js:5:3 rss = 55083008 Completed consolecopy
Исходное значение <file>:<line>[:<col>], переданное в --probe, может быть разрешено в другое местоположение, чтобы обеспечить возможность приостановки, либо ему могут соответствовать несколько загруженных скриптов, поэтому фактическое место вычисления помогает однозначно интерпретировать результаты.
Примитивные результаты выводятся напрямую, а для объектов и массивов, если они доступны, используются данные предварительного просмотра из протокола Chrome DevTools. Для остальных непримитивных значений используется строка description протокола Chrome DevTools. Ошибки выражений записываются как строки [error] ... и не приводят к сбою всего сеанса. Если требуется более гибкое форматирование текста, оберните выражение в JSON.stringify(...) или util.inspect(...).
При использовании --json вывод имеет следующую структуру:
$ node inspect --json --probe cli.js:5 --expr 'rss' cli.js
{"v":2,"probes":[{"expr":"rss","target":{"suffix":"cli.js","line":5}}],"results":[{"probe":0,"event":"hit","hit":1,"location":{"url":"file:///path/to/cli.js","line":5,"column":3},"result":{"type":"number","value":55443456,"description":"55443456"}},{"probe":0,"event":"hit","hit":2,"location":{"url":"file:///path/to/cli.js","line":5,"column":3},"result":{"type":"number","value":55574528,"description":"55574528"}},{"event":"completed"}]}
consolecopy
{
"v": 2, // Probe JSON schema version.
"probes": [
{
"expr": "rss", // The expression paired with --probe.
"target": {
// The user's probe specification. `suffix` is the raw <file> passed
// to --probe and is matched as a path-separator-anchored suffix
// against every loaded script's URL. `column` is present only if the
// user supplied `:col`. The actual evaluation location may differ
// from the target and will be reported in each hit's `location` field.
"suffix": "cli.js",
"line": 5
}
}
],
"results": [
{
"probe": 0, // Index into probes[].
"event": "hit", // Hit events are recorded in observation order.
"hit": 1, // 1-based hit count for this probe.
"location": {
// The actual location where the execution is paused to evaluate
// the expression of the probe. This may differ from the probe's
// target due to pausability adjustments or multiple matches.
"url": "file:///path/to/cli.js",
"line": 5,
"column": 3
},
"result": {
"type": "number",
"value": 55443456,
"description": "55443456"
}
// If the probe expression throws, fails, or never completes, the entry
// carries an `error` field instead of `result` with the shape
// `{ message: string, details?: object }`. The `message` and `details`
// content is informational only and may change between releases.
},
{
"probe": 0,
"event": "hit",
"hit": 2,
"location": { "url": "file:///path/to/cli.js", "line": 5, "column": 3 },
"result": {
"type": "number",
"value": 55574528,
"description": "55574528"
}
},
{
"event": "completed"
// The final entry is always a terminal event, for example:
// 1. { "event": "completed" }
// 2. { "event": "miss", "pending": [0, 1] }
// 3. {
// "event": "timeout",
// "pending": [0],
// "error": {
// "code": "probe_timeout",
// "message": "Timed out after 30000ms waiting for probes: app.js:10"
// }
// }
// 4. {
// "event": "error",
// "pending": [0],
// "error": {
// "code": "probe_target_exit",
// "exitCode": 1,
// "stderr": "Error: boom",
// "message": "Target exited with code 1 before probes: app.js:10"
// }
// }
// 5. {
// "event": "error",
// "pending": [1],
// "error": {
// "code": "probe_failure",
// "probe": 0,
// "stderr": "...",
// "message": "Target process exited during probe evaluation before probes: app.js:12. If the failure repeats, review the probe expression.",
// "details": { "lastCdpMethod": "Debugger.evaluateOnCallFrame" }
// }
// }
}
]
}
jsoncopyВывод и коды завершения
В режиме зондирования в stdout выводится только итоговый отчёт зондирования; вывод stdout/stderr дочернего процесса подавляется. По завершении сеанса зондирования процесс зондирования обычно завершается с кодом 0 и выводит итоговый отчёт в stdout. Если дочерний процесс завершается с ненулевым кодом до окончания сеанса зондирования или сеанс не удаётся завершить по другой причине, в итоговом отчёте фиксируется терминальное событие error.
Если значение error.code равно 'probe_failure' или 'probe_timeout', процесс зондирования завершается с ненулевым кодом, что указывает на возможную неполноту записанных срабатываний. В этом случае error.message будет содержать подсказки по восстановлению, а error.probe, если он присутствует, будет индексом в массиве probes отчёта, который в качестве подсказки указывает на возможный проблемный зонд.
Недопустимые аргументы, а также критические ошибки запуска или подключения могут привести к завершению процесса зондирования с ненулевым кодом и выводу сообщения об ошибке в stderr без итогового отчёта зондирования.
Зондирование нескольких выражений в одной точке выполнения
Если несколько пар --probe/--expr имеют одинаковое значение --probe, выражения будут вычислены при одной и той же приостановке в порядке их появления в командной строке.
// app.js
const x = { x: 42 }; // line 2
const y = { y: 35 }; // line 3
const z = { ...x, ...y }; // line 4
jscopy
$ node inspect --probe app.js:4 --expr 'x' --probe app.js:4 --expr 'y' -- app.js consolecopy
Выводит
Hit 1 at file:///path/to/app.js:4:1
x = {x: 42}
Hit 1 at file:///path/to/app.js:4:1
y = {y: 35}
Completed
textcopy
$ node inspect --probe app.js:4 --expr 'x' --probe app.js:4 --expr 'y' --json --preview -- app.js consolecopy
Выводит
{"v":2,"probes":[{"expr":"x","target":{"suffix":"app.js","line":4}},{"expr":"y","target":{"suffix":"app.js","line":4}}],"results":[{"probe":0,"event":"hit","hit":1,"location":{"url":"file:///path/to/app.js","line":4,"column":1},"result":{"type":"object","description":"Object","preview":{"type":"object","description":"Object","overflow":false,"properties":[{"name":"x","type":"number","value":"42"}]}}},{"probe":1,"event":"hit","hit":1,"location":{"url":"file:///path/to/app.js","line":4,"column":1},"result":{"type":"object","description":"Object","preview":{"type":"object","description":"Object","overflow":false,"properties":[{"name":"y","type":"number","value":"35"}]}}},{"event":"completed"}]}
jsoncopyВыбор местоположения зонда
При достижении местоположения зонда выражения вычисляются в его лексической области видимости. Не следует зондировать переменную, объявленную с помощью let или const, непосредственно в месте её объявления: это приведёт к ReferenceError из-за обращения к переменной в её временной мёртвой зоне (TDZ).
// app.js const x = 42; // line 2 console.log(x); // line 3 jscopy
$ node inspect --probe app.js:1 --expr 'x' app.js Hit 1 at file:///path/to/app.js:1:1 [error] x = ReferenceError: Cannot access 'x' from debugger ... Completed consolecopy
Вместо этого установите зонд в месте, где переменная уже инициализирована:
$ node inspect --probe app.js:3 --expr 'x' app.js Hit 1 at file:///path/to/app.js:3:1 x = 42 Completed consolecopy
Аргумент <file> сопоставляется с окончанием пути каждого URL загруженного скрипта; границей служит разделитель пути. Если передать только базовое имя файла, ему будут соответствовать все загруженные скрипты с таким именем — аналогично тому, как обычно сопоставляются точки останова в нативных отладчиках. Частичный путь позволяет сузить поиск. Например:
project/ - src/utils.js - lib/utils.js textcopy
--probe utils.js:10 привязывается к обоим файлам и создаёт по одному срабатыванию для каждого совпадения. Каждое срабатывание содержит собственное поле location, указывающее, где именно было выполнено выражение, что позволяет потребителям точно соотнести результат с одним из двух файлов. Чтобы однозначно определить файл при привязке, укажите более полный путь, соответствующий только нужному файлу:
$ node inspect --probe src/utils.js:10 --expr 'x' main.js # matches only src/utils.js consolecopy
Дополнительные сведения об использовании
Интеграция инспектора V8 с Node.js
Интеграция инспектора V8 позволяет подключать Chrome DevTools к экземплярам Node.js для отладки и профилирования. Она использует протокол Chrome DevTools.
Инспектор V8 можно включить, передав флаг --inspect при запуске приложения Node.js. С помощью этого флага также можно указать другой порт, например --inspect=9222 будет принимать подключения DevTools на порту 9222.
Флаг --inspect запускает выполнение кода непосредственно перед подключением отладчика. Это означает, что код начнёт выполняться до того, как вы сможете начать отладку, что может быть нежелательно, если нужно отлаживать программу с самого начала.
В таких случаях можно выбрать один из двух вариантов:
-
Флаг
--inspect-wait: этот флаг приостанавливает выполнение кода, пока не подключится отладчик. Это позволяет начать отладку с самого начала выполнения. -
Флаг
--inspect-brk: в отличие от--inspect, этот флаг останавливает выполнение на первой строке кода сразу после подключения отладчика. Это полезно, если нужно пошагово отлаживать код с самого начала, не допуская его выполнения до начала отладки.
Поэтому при выборе между --inspect, --inspect-wait и --inspect-brk учитывайте, нужно ли вам немедленно начать выполнение кода, дождаться подключения отладчика или остановиться на первой строке для пошаговой отладки.
$ node --inspect index.js Debugger listening on ws://127.0.0.1:9229/dc9010dd-f8b8-4ac5-a510-c1a114ec7d29 For help, see: https://nodejs.org/learn/getting-started/debugging consolecopy
(В приведённом выше примере UUID dc9010dd-f8b8-4ac5-a510-c1a114ec7d29 в конце URL генерируется динамически и меняется от одного сеанса отладки к другому.)
© Joyent, Inc. and other Node contributors
Licensed under the MIT License.
Node.js is a trademark of Joyent, Inc. and is used with its permission.
We are not endorsed by or affiliated with Joyent.
https://nodejs.org/api/debugger.html