Debugging JavaScript в DevTools
Отладка JS через breakpoints, пошаговое выполнение, watch expressions и call stack
Зачем нужно
- Находить баги без
console.logповсюду - Понимать поток выполнения программы
- Инспектировать значения переменных в runtime
- Отлаживать асинхронный код
Где используется
- Отладка любого JavaScript-кода в браузере
- Поиск причин неправильного поведения
- Анализ сложной логики
Предпосылки
- Console tab
- Базовый JavaScript
Sources Panel
Панель Sources → Page → файловая структура сайта:
Page
├── top
│ ├── example.com
│ │ ├── index.html
│ │ ├── app.js ← ваш код
│ │ └── style.css
│ └── cdn.example.com
│ └── library.js
└── Snippets
Ctrl+P — быстрый поиск файла (как в VS Code).
Breakpoints (точки останова)
Обычный breakpoint
Клик на номер строки в Sources → синяя метка:
function calculateTotal(items) {
let total = 0; // ← breakpoint здесь
for (const item of items) {
total += item.price; // выполнение остановится
}
return total;
}
Когда выполнение достигнет этой строки — пауза.
В коде (debugger)
function processData(data) {
debugger; // ← остановка здесь (работает как breakpoint)
return data.map(item => item.value);
}
Не забудьте убрать
debuggerперед коммитом!
Conditional Breakpoint
Правый клик на номер строки → "Add conditional breakpoint":
// Остановиться только когда i === 50
for (let i = 0; i < 100; i++) {
processItem(items[i]); // condition: i === 50
}
Logpoint
Правый клик → "Add logpoint" — выводит в Console без остановки:
// Logpoint: "Item price:", item.price
for (const item of items) {
total += item.price; // logpoint вместо console.log
}
Типы Breakpoints
DOM Breakpoints
В Elements tab → Right-click → Break on:
- Subtree modifications — изменение дочерних элементов
- Attribute modifications — изменение атрибутов
- Node removal — удаление узла
Event Listener Breakpoints
Sources → Event Listener Breakpoints:
- Mouse → click
- Keyboard → keydown
- Timer → setTimeout
- XHR/Fetch → любой запрос
XHR/Fetch Breakpoints
Sources → XHR/Fetch Breakpoints → Add:
URL contains: /api/users
Остановка при запросе к URL, содержащему /api/users.
Exception Breakpoints
Кнопка "Pause on exceptions" (⏸):
- Pause on caught exceptions — остановка на любом throw
- Pause on uncaught exceptions — только на необработанных
Пошаговое выполнение
Когда код остановлен на breakpoint:
| Кнопка | Действие | Горячая клавиша |
|---|---|---|
| ▶ Resume | Продолжить до следующего breakpoint | F8 |
| ⤵ Step Over | Следующая строка (не заходя в функции) | F10 |
| ⤓ Step Into | Зайти внутрь функции | F11 |
| ⤒ Step Out | Выйти из текущей функции | Shift+F11 |
| → Step | Следующий шаг (включая async) | F9 |
Пример
function main() {
const data = fetchData; // F10 — перешагнуть
const result = process(data); // F11 — зайти внутрь process
display(result);
}
function process(data) {
// Мы здесь после Step Into
const filtered = data.filter(Boolean); // F10
return filtered.map(transform); // Shift+F11 — выйти обратно в main
}
Инспекция данных
Scope (область видимости)
При остановке на breakpoint — панель Scope:
Local:
total = 150
item = {name: "Widget", price: 50}
Closure:
config = {tax: 0.2}
Global:
window
document
Watch Expressions
Панель Watch → + Add expression:
items.length
total > 100
currentUser?.name
response.status === 200
Выражения обновляются на каждом шаге.
Hover
Наведите мышь на переменную в коде → всплывающее окно с текущим значением.
Console при остановке
Console работает в контексте текущего breakpoint:
// Можно обращаться к локальным переменным
> total // 150
> items[0] // {name: "Widget", price: 50}
> items.length // 3
Call Stack (стек вызовов)
Показывает цепочку вызовов до текущей точки:
▶ calculateTotal (app.js:15) ← текущая позиция
processOrder (app.js:8)
handleSubmit (app.js:3)
(anonymous) (index.html:25)
Клик на любой фрейм → переход к тому месту в коде.
Async call stack
DevTools показывает полный async-стек:
▶ processResponse (api.js:20)
--- async ---
fetchUsers (api.js:10) ← await fetch(...)
--- async ---
handleClick (app.js:5)
Blackboxing (игнорирование библиотек)
Чтобы Step Into не заходил в код библиотек:
Settings → Blackboxing → Add pattern:
/node_modules/
/jquery\.js$
/react-dom/
Или: Right-click на файл в Call Stack → "Add script to ignore list".
Частые ошибки
- Отлаживать через
console.log— breakpoints точнее и не засоряют код - Забывать
debuggerв коде — попадёт в production - Не использовать conditional breakpoints — останавливаться на каждой итерации цикла
- Не смотреть Call Stack — не понимать откуда вызвана функция
- Не использовать Blackboxing — Step Into уходит в код React/jQuery
Практика
- Поставьте breakpoint в своём JS-коде и остановите выполнение
- Пройдите 10 шагов через Step Over / Step Into / Step Out
- Изучите панель Scope — найдите значения переменных
- Добавьте Watch Expression и проследите как оно меняется
- Используйте Console при остановке для проверки значений
- Поставьте Conditional Breakpoint, который срабатывает только на определённом условии
- Поставьте Event Listener Breakpoint на click