Мы, как разработчики, пишем код. Теперь мы не просто пишем, мы также проверяем, работает ли написанный код. Мы тратим много времени и прилагаем много усилий, чтобы наши программы делали то, что должны делать. Этот процесс отладки часто бывает болезненным. Особенно, если мы не используем надлежащие инструменты. Чтобы помочь с этой проблемой, в сегодняшней статье представлена Deb.js , небольшая библиотека JavaScript, которая помогает вам выполнять отладку из браузера.
Пример
Давайте начнем с создания простой страницы с некоторым взаимодействием JavaScript. Мы создадим форму с двумя полями и кнопкой. Как только пользователь нажмет на кнопку, мы соберем данные и выведем сообщение в консоль. Вот разметка страницы:
1
2
3
4
5
6
7
8
|
<form>
<label>Name:</label>
<input type=»text» name=»name» />
<label>Address:</label>
<input type=»text» name=»address» />
<input type=»button» value=»register» />
</form>
<div data-element=»output»></div>
|
Чтобы упростить пример, мы будем использовать jQuery для выбора DOM и событий. Мы обернем функциональность в следующем модуле:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
var Module = {
collectData: function(cb) {
var name = $(‘[name=»name»]’).val();
var address = $(‘[name=»address»]’).val();
if(name != » && address != ») {
cb(null, { name: name, address: address });
} else {
cb({msg: ‘Missing data’});
}
},
error: function(err) {
$(‘[data-element=»output»]’).html(err.msg);
},
success: function(data) {
$(‘[data-element=»output»]’).html(‘Hello ‘ + data.name + ‘!’);
}
}
|
Функция collectData
получает значение из полей и проверяет, набрал ли пользователь что-либо. Если нет, то он запускает обратный вызов с объектом, содержащим короткое сообщение об ошибке. Если все в порядке, он отвечает null
в качестве первого параметра и другим объектом в качестве второго, содержащего данные. Разработчик, использующий модуль, должен проверить, не передан ли объект ошибки. Если нет, тогда начните использовать второй полученный аргумент. Например:
1
2
3
4
5
6
7
8
9
|
$(‘[value=»register»]’).on(‘click’, function() {
Module.collectData(function(err, data) {
if(typeof err === ‘object’) {
Module.error(err);
} else {
Module.success(data);
}
});
});
|
Итак, мы проверяем, является ли параметр err
объектом, и если да, то мы показываем сообщение. Если мы внимательно посмотрим на код, мы обнаружим проблему, но давайте проверим, как все работает:
Когда данных нет, наш скрипт работает как положено. Под формой отображается текст с Missing data
. Однако, если мы добавим что-то в поля и нажмем кнопку, мы получим: Uncaught TypeError: Cannot read property 'msg' of null
, message. Теперь давайте выследим ошибку и удалим ее.
Традиционный подход
В Google Chrome есть замечательные инструменты для решения таких проблем. Мы можем нажать на сгенерированную ошибку и посмотреть ее след стека. Мы могли бы даже пойти в то место, где произошла ошибка.
Похоже, что метод error
нашего модуля получает что-то, что является null
. И, конечно же, null
не имеет свойства msg
. Вот почему браузер выдает ошибку. Есть только одно место, где вызывается функция error
. Давайте установим точку останова и посмотрим, что произойдет:
Похоже, мы получили правильный объект data
и error
равна null
, что является правильным поведением. Итак, проблема должна быть где-то в предложении if
. Давайте добавим console.log
и посмотрим, пойдем ли мы в правильном направлении:
1
2
3
4
5
6
7
8
|
Module.collectData(function(err, data) {
console.log(typeof err);
if(typeof err === ‘object’) {
Module.error(err);
} else {
Module.success(data);
}
});
|
И действительно, typeof err
возвращает object
. Вот почему мы всегда показываем ошибку.
И вуаля, мы нашли проблему. Нам просто нужно изменить оператор if
на if (err)
и наш маленький эксперимент будет работать как положено.
Однако такой подход иногда бывает сложным, поэтому рассмотрим следующие указатели:
- Как мы видели, мы закончили регистрацию переменной. Таким образом, установка точки останова не всегда достаточно. Мы должны прыгнуть на консоль тоже. В то же время мы должны взглянуть на наш редактор кода и панель отладки Chrome. Это несколько разных мест для работы, которые могут раздражать.
- Это также проблема, если в консоль вошло много данных. Иногда сложно найти необходимую информацию.
- Этот подход не помогает, если у нас есть проблемы с производительностью. Чаще всего нам нужно знать время выполнения.
Остановка программы во время выполнения и проверка ее состояния бесценны, но у Chrome нет возможности узнать, что мы хотим видеть. Как и в нашем случае, мы должны дважды проверить предложение if
. Разве не было бы лучше, если бы у нас был инструмент, напрямую доступный из нашего кода? Библиотека, которая приносит подобную информацию, как отладчик, но живет внутри консоли? Ну, Deb.js может быть ответом на этот вопрос.
Использование Deb.js
Deb.js — это небольшой кусочек JavaScript-кода, уменьшенный до 1,5 килобайта, который отправляет информацию на консоль. Он может быть прикреплен к каждой функции и распечатывает:
- Место и время выполнения функции
- Трассировки стека
- Форматированный и сгруппированный вывод
Давайте посмотрим, как выглядит наш пример, когда мы используем Deb.js:
Мы снова видим точные переданные аргументы и трассировку стека. Однако обратите внимание на изменения в консоли. Мы работаем над нашим кодом, выясним, где может быть проблема и добавим .deb()
после определения функции. Обратите внимание, что тип err
размещен внутри функции. Таким образом, нам не нужно искать его. Вывод также сгруппирован и раскрашен. Каждая функция, которую мы хотим отладить, будет напечатана другим цветом. Давайте теперь исправим нашу ошибку и разместим еще один deb()
чтобы посмотреть, как он выглядит.
Теперь у нас есть две функции. Мы могли бы легко различить их, потому что они разных цветов. Мы видим их ввод, вывод и время выполнения. Если есть какие-либо операторы console.log
, мы увидим их внутри функций, в которых они встречаются. Существует даже возможность оставить описание для лучшего распознавания функций.
Обратите внимание, что мы использовали debc
а не deb
. Это та же функция, но выход рушится. Если вы начнете использовать Deb.js , вы очень скоро обнаружите, что вы не всегда хотите видеть все.
Как создавался Deb.js
Первоначальная идея пришла из сообщения в блоге Реми Шарпа о том, где найти console.log
. Он предположил, что мы можем создать новую ошибку и получить оттуда трассировку стека:
01
02
03
04
05
06
07
08
09
10
11
12
|
[‘log’, ‘warn’].forEach(function(method) {
var old = console[method];
console[method] = function() {
var stack = (new Error()).stack.split(/\n/);
// Chrome includes a single «Error» line, FF doesn’t.
if (stack[0].indexOf(‘Error’) === 0) {
stack = stack.slice(1);
}
var args = [].slice.apply(arguments).concat([stack[1].trim()]);
return old.apply(console, args);
};
})
|
Оригинальный пост можно найти в блоге Реми . Это особенно полезно, если мы разрабатываем в среде Node.js.
Итак, имея в руках трассировку стека, мне как-то нужно было вставить код в начало и конец функции. Это когда образец, используемый в вычисляемых свойствах Эмбер, всплыл в моей голове. Это хороший способ исправить оригинальный Function.prototype
. Например:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
Function.prototype.awesome = function() {
var original = this;
return function() {
console.log(‘before’);
var args = Array.prototype.slice.call(arguments, 0);
var res = original.apply(this, args);
console.log(‘after’);
return res;
}
}
var doSomething = function(value) {
return value * 2;
}.awesome();
console.log(doSomething(42));
|
Ключевое слово this
в нашем патче указывает на оригинальную функцию. Мы можем запустить его позже, а это именно то, что нам нужно, потому что мы можем отслеживать время до и после выполнения. В то же время мы возвращаем нашу собственную функцию, которая действует как прокси. Мы использовали .apply(this, args)
, чтобы сохранить контекст и переданные аргументы. И, к счастью, к совету Реми, мы можем получить трассировку стека
Остальная часть реализации Deb.js — просто украшение. Некоторые браузеры поддерживают console.group
и console.groupEnd
что очень помогает для визуального представления логирования. Chrome даже дает нам возможность раскрашивать напечатанную информацию в разные цвета.
Резюме
Я верю в использование отличных инструментов и инструментов. Браузеры — это умные инструменты, разработанные умными людьми, но иногда нам нужно нечто большее. Deb.js стал крошечной утилитой и успешно помог мне ускорить процесс отладки. Это, конечно, с открытым исходным кодом. Не стесняйтесь сообщать о проблемах или выдвигать запросы .
Спасибо за прочтение.