Отладка — неизбежный и зачастую очень длительный этап разработки любого приложения. Клиентская веб-разработка в этом смысле не исключение, более того, здесь этот вопрос стоит особенно остро. Если при отладке backend’а область действий программиста ограничена инструментом разработки, то в frontend’е задачу отладки осложняют многочисленные внешние факторы — браузеры. С их многообразием и различиями приходится волей-неволей считаться любому веб-разработчику. Об этом и пойдет речь далее.
Данная статья не претендует на оригинальность. Вполне возможно, что что-то подобное уже было написано ранее кем-то другим. Единственной целью при ее написании было желание автора поделиться своим опытом в отладке JavaScript. Автор уважает мнения других хабрапользователей и никому не навязывает свою точку зрения.
Проблема кроссбраузерности в отладке уже неоднократно рассматривалась на Хабре (1, 2, 3 и др.). Но к сожалению, во всех статьях, ранее освещавших этот вопрос, применялся один и тот же подход к его решению: использование инструментов отладки, специфичных для каждого браузера. Конечно, никто еще не отменял console.log — простой, и в некотором смысле кроссбраузерный, инструмент, хорошо помогающий в отладке. Но его применение опять-таки ограничено наличием в браузере средств отладки. Особенно это касается мобильных устройств, в которых получить доступ к средствам отладки не так просто, а иногда и вовсе невозможно.
Я давно уже привык использовать для клиентской отладки Firefox с его замечательным плагином Firebug. И да простят меня сторонники всех остальных браузеров, меня никогда не радовала необходимость разбираться с инструментами отладки в других браузерах. Я был бы рад найти аналог console.log, работающий в любом браузере и не требующий установки и изучения специальных инструментов.
И вот однажды, после долгих мытарств с отладкой в очередном экзотическом для меня браузере, мне пришла в голову одна идея, простая до безобразия: Единственный способ гарантировать доступ к отладочной информации в любом браузере — выводить эту информацию прямо в окне документа, вместе с остальным его содержимым.
Я знаю как это выглядит на первый взгляд. Но не спешите лезть в карман за минусами. Прошу вас прежде дочитать эту статью до конца.
Да, это напоминает отладку в худших традициях PHP-быдлокодерства — вывод через echo/print. Но в отличие от серверной отладки, в frontend’е этим выводом можно управлять с большой гибкостью (так что он не будет разбросан по всей странице в неприглядном виде).
Да, этот способ далеко не идеален. Главный его недостаток состоит в том, что такой отладочный вывод необходимо удалять после окончания проверки (в production-версии разумеется его никак нельзя оставлять). Но вместе с тем, задача очистки кода от отладочного вывода не представляет особой сложности. Это легко можно делать вручную, но лучше все-таки использовать для этого программные средства (скрипты).
В результате этих размышлений мной был написан небольшой код для замены функций console.log. Я называю его по привычке jQuery плагином, хотя по сути это конечно же не так: он ничего не добавляет к функциональности jQuery, хотя и использует его средства. Вот этот код:
if (!window.herelog && window.jQuery) {
window.herelog= {
oOut: null,
bOn: false,
fnAction: null,
init: function(oParams) {
if (this.oOut) return;
var oCfg= {
oPlace: null,
bInitOn: true,
bInitShow: false,
fnAction: null,
oLanguage: {title: 'windowlog:',
on: 'ON', show: 'Show', clear: 'Clear', action: 'Action'
}
};
if (oParams) jQuery.extend(true, oCfg, oParams);
this.bOn= oCfg.bInitOn;
this.fnAction= (typeof oCfg.fnAction == 'function')? oCfg.fnAction : null;
var oCtrl= jQuery(
'<form class="windowlog-ctrl" onsubmit="return false">'+
'<h1>'+ oCfg.oLanguage.title+ '</h1>'+
' <label><input type="checkbox" class="wl-on"'+
(this.bOn? ' checked' : '')+ '/>'+ oCfg.oLanguage.on+ '</label>'+
' <label><input type="checkbox" class="wl-show"'+
(oCfg.bInitShow? ' checked' : '')+ '/>'+ oCfg.oLanguage.show+ '</label>'+
' <button class="wl-clear">'+ oCfg.oLanguage.clear+ '</button>'+
(this.fnAction?
' <button class="wl-action">'+ oCfg.oLanguage.action+ '</button>' : '')+
'</form>'
);
this.oOut= jQuery(
'<div class="windowlog-output" style="display:'+
(oCfg.bInitShow? 'block': 'none')+ '"/>'
);
jQuery(oCfg.oPlace? oCfg.oPlace : (document.body? document.body : document))
.append(oCtrl).append(this.oOut);
var self= this;
oCtrl.find('input.wl-on').change(function() {
self.bOn= !self.bOn;
});
oCtrl.find('input.wl-show').change(function() {
self.oOut.toggle();
});
oCtrl.find('button.wl-clear').click(function() {
self.oOut.html('');
});
if (this.fnAction) oCtrl.find('button.wl-action').click(function() {
self.fnAction.call(this, self.oOut.eq(0));
});
},
add: function(text) {
if (this.oOut && this.bOn) this.oOut.append('<p>'+ text+'</p>');
}
};
}
Как видно, jQuery используется только во внутренней реализации плагина, внешний же его интерфейс не зависит от jQuery. Так что содержание плагина может быть переписано под использование только чистого JavaScript’а. Возможно, в будущем я так и сделаю. Пока же он меня вполне устраивает и в таком виде.
Как использовать
Инициализация (настройка):
herelog.init(oSettings); // oSettings - объект настройки.
Добавление информации в отладочный вывод:
herelog.add(text);
Список свойств (параметров) объекта настройки:
Имя свойства | Тип | Описание |
---|---|---|
oPlace | Object/String | DOM элемент (либо определяющий его jQuery-селектор), в котором будет помещаться блок отладочного вывода. В случае отсутствия этого свойства данный блок будет помещен в конце тела текущего документа |
bInitOn | Boolean | Начальное состояние переключателя «On» (включить отладочный вывод). |
bInitShow | Boolean | Начальное состояние переключателя «Show» (показывать отладочную информацию). |
fnAction | Callback Function | Функция обратного вызова, вызываемая для выполнения определенного действия с отладочной информацией. |
Расскажу подробнее о функции обратного вызова. Она должна иметь следующий формат:
function (oElem) {...}
где oElem — DOM элемент, соответствующий блоку отладочного вывода.
Какое действие будет выполняться при вызове этой функции — решать вам. На мой взгляд наиболее логичным выглядит отправка через AJAX отладочной информации на сервер разработчика, что собственно и делается (вернее, эмулируется) в примере ниже.
Здесь можно посмотреть мини-демонстрацию использования моего логгера на примере плагина Tiny Scrollbar (как-то раз мне понадобилось модифицировать этот плагин под собственные нужды, и тогда этот логгер мне очень пригодился).
Заключение
Описанный в данной статье способ призван помочь в устранении ошибок в веб-приложениях, связанных с особенностями различных браузеров и их платформ. Он может быть полезен при отладке различных событий, выявления нефатальных ошибок JavaScript, а также ошибок отображения (верстки).
Следует отметить, что существуют и другие, более «продвинутые» и изысканные решения, например от Yahoo: YUI 2 Logger, YUI 3 Console.
Спасибо за внимание.
Автор: xmeoff