Введение
Мощная особенность, которая делает JavaScript уникальным, — это его способность работать асинхронно с помощью функций обратного вызова. Назначение асинхронных обратных вызовов позволяет писать код, управляемый событиями, но это также делает отслеживание ошибок утомительным занятием, поскольку JavaScript не выполняется линейным образом.
К счастью, теперь в Chrome DevTools вы можете просмотреть полный стек вызовов асинхронных обратных вызовов JavaScript!
После включения функции стека асинхронных вызовов в DevTools вы сможете детализировать состояние вашего веб-приложения в различные моменты времени. Пройдите полную трассировку стека для некоторых прослушивателей событий, setInterval
, setTimeout
, XMLHttpRequest
, промисов, requestAnimationFrame
, MutationObservers
и других.
Проходя трассировку стека, вы также можете анализировать значение любой переменной в данный конкретный момент выполнения во время выполнения. Это как машина времени для выражений ваших часов!
Давайте включим эту функцию и рассмотрим несколько таких сценариев.
Включить асинхронную отладку в Chrome
Попробуйте эту новую функцию, включив ее в Chrome. Перейдите на панель «Источники» Chrome Canary DevTools.
Рядом с панелью «Стек вызовов» с правой стороны появился новый флажок «Асинхронный». Установите этот флажок, чтобы включить или отключить асинхронную отладку. (Хотя, как только он будет включен, вы, возможно, никогда не захотите его выключать.)
Захват событий таймера с задержкой и ответов XHR
Вероятно, вы уже видели это раньше в Gmail:
Если при отправке запроса возникла проблема (либо на сервере, либо на стороне клиента возникли проблемы с сетевым подключением), Gmail автоматически попытается повторно отправить сообщение после небольшого таймаута.
Чтобы увидеть, как стеки асинхронных вызовов могут помочь нам анализировать отложенные события таймера и ответы XHR, я воссоздал этот процесс с помощью макета примера Gmail . Полный код JavaScript можно найти по ссылке выше, но порядок действий следующий:
Если посмотреть только на панель «Стек вызовов» в предыдущих версиях DevTools, точка останова в postOnFail()
даст вам мало информации о том, откуда вызывался postOnFail()
. Но посмотрите на разницу при включении асинхронных стеков:
Если включены асинхронные стеки вызовов, вы можете просмотреть весь стек вызовов, чтобы легко увидеть, был ли запрос инициирован из submitHandler()
(который происходит после нажатия кнопки отправки) или из retrySubmit()
(который происходит после задержки setTimeout()
). :
Наблюдайте за выражениями асинхронно
Когда вы проходите полный стек вызовов, ваши наблюдаемые выражения также обновляются, чтобы отражать состояние, в котором они находились в тот момент!
Оцените код из прошлых областей
Помимо простого просмотра выражений, вы можете взаимодействовать со своим кодом из предыдущих областей прямо на панели консоли DevTools JavaScript.
Представьте, что вы Доктор Кто и вам нужна небольшая помощь, чтобы сравнить часы, которые были до того, как вы попали в ТАРДИС, и часы «сейчас». С консоли DevTools вы можете легко оценивать, сохранять и выполнять расчеты значений, полученных в разных точках выполнения.
Использование DevTools для управления вашими выражениями сэкономит вам время от необходимости возвращаться к исходному коду, вносить изменения и обновлять браузер.
Разгадать связанные обещания
Если вы думали, что предыдущий макет потока Gmail было трудно разгадать без включенной функции асинхронного стека вызовов, можете ли вы представить, насколько сложнее это было бы с более сложными асинхронными потоками, такими как цепочки обещаний? Давайте вернемся к последнему примеру урока Джейка Арчибальда по обещаниям JavaScript .
Вот небольшая анимация обхода стеков вызовов в примере Джейка async-best-example.html .
Получите ценную информацию о вашей веб-анимации
Давайте углубимся в архивы HTML5Rocks. Помните анимацию «Leaner, Meaner, Faster» Пола Льюиса с requestAnimationFrame ?
Откройте демо-версию requestAnimationFrame и добавьте точку останова в начале метода update() (около строки 874) файла post.html. С помощью стеков асинхронных вызовов мы получаем гораздо больше информации о requestAnimationFrame , включая возможность пройти весь путь обратно к инициирующему обратному вызову события прокрутки.
Отслеживайте обновления DOM при использовании MutationObserver
MutationObserver
позволяет нам наблюдать изменения в DOM. В этом простом примере , когда вы нажимаете кнопку, новый узел DOM добавляется к <div class="rows"></div>
.
Добавьте точку останова в nodeAdded()
(строка 31) в demo.html. Если включены асинхронные стеки вызовов, вы можете вернуть стек вызовов через addNode()
к начальному событию щелчка.
Советы по отладке JavaScript в стеках асинхронных вызовов
Назовите свои функции
Если вы склонны назначать все свои обратные вызовы как анонимные функции, вы можете вместо этого дать им имя, чтобы упростить просмотр стека вызовов.
Например, возьмем такую анонимную функцию:
window.addEventListener('load', function() {
// do something
});
И дайте ему имя, например windowLoaded()
:
window.addEventListener('load', function <strong>windowLoaded</strong>(){
// do something
});
Когда событие загрузки срабатывает, оно отображается в трассировке стека DevTools с именем функции вместо загадочного « (анонимная функция) ». Это позволяет с первого взгляда увидеть, что происходит в трассировке стека.
Изучите дальше
Напомним, что это все асинхронные обратные вызовы, в которых DevTools отображает полный стек вызовов:
- Таймеры : вернитесь туда, где были инициализированы
setTimeout()
илиsetInterval()
. - XHRs : вернитесь туда, где был вызван
xhr.send()
. - Кадры анимации : вернитесь туда, где был вызван
requestAnimationFrame
. - Обещания : вернитесь туда, где обещание было выполнено.
- Object.observe : вернуться туда, где изначально был привязан обратный вызов наблюдателя.
- MutationObservers : вернитесь туда, где было запущено событие наблюдателя мутаций.
- window.postMessage() : обход вызовов обмена сообщениями внутри процесса.
- DataTransferItem.getAsString()
- API файловой системы
- ИндекседБД
- ВебSQL
- Подходящие события DOM через
addEventListener()
: вернитесь туда, где событие было запущено. Из соображений производительности не все события DOM поддерживают функцию стеков асинхронных вызовов. Примеры доступных в настоящее время событий: «прокрутка», «хеш-изменение» и «выбор-изменение». - Мультимедийные события через
addEventListener()
: вернитесь туда, где было запущено событие. Доступные мультимедийные события включают в себя: аудио- и видеособытия (например, «воспроизведение», «пауза», «изменение скорости»), события WebRTC MediaStreamTrackList (например, «addtrack», «removetrack») и события MediaSource (например, «sourceopen»).
Возможность видеть полную трассировку стека ваших обратных вызовов JavaScript должна держать вас в напряжении. Эта функция в DevTools будет особенно полезна, когда происходит несколько асинхронных событий по отношению друг к другу или если из асинхронного обратного вызова выдается неперехваченное исключение.
Попробуйте в Chrome. Если у вас есть отзывы об этой новой функции, напишите нам в систему отслеживания ошибок Chrome DevTools или в группу Chrome DevTools .