середу, квітня 29, 2009

Искусство JavaScript ошибок: JavaScript error handling anti-pattern

Есть одна область в javascript программировании, где я ощущаю недостаток дискуссии - это отслеживание ошибок. В то время как многие девелоперы занимаются дебагом ошибок в серверных языках, в JS это делают не многие. Я постараюсь поднять интерес разработчиков к обработке javascript ошибок.

Одно из решений, это введение дебаг мода для приложения на JS. Идея такая, что если дебаг мод установлен в false, ошибки происходят сами собой, если же дебаг мод true - ошибки могут логироваться на сервере или алертом показывать свое присутствие с указанием строки и причины ошибки. Очень полезно для IE.


Пример:
function doSomething(value){
try {
process(value);
} catch (ex){
if (debugMode){
throw ex;
} else {
log(1, "doSomething(): " + ex.message);
}
}
}
Идея примера такова, что если возникла ошибка, то в зависимости от установленного дебаг мода ошибка или логируется или просто показывается. Сейчас, я постараюсь объяснить всю уязвимость данной идеи.

Если ошибка возникнет в функции process(), она будет перехвачена в функции doSomething() и в зависимости от дебаг мода сгенерируется или залогируется, тем самым разрушит call stack. Ошибка будет слишком далека от актуального события, которое нам и нужно отдебажить. Вся полезная информация, которая могла бы быть решением будет утеряна, так как мы выйдем из функции process(). Используя этот код, ваш дебагер будет обрывать выполнение программы в строке содержащей throw ex, в то время как вы хотите оборвать выполнение в самой функции process().

Мое решение - это код, который будет скорее предотвращать полезный дебаг, чем разрешать его.
Есть два способа решения этой проблемы:

1 (Галимый):
function doSomething(value){
if (!debugMode){
process(value);
} else {
try {
process(value);
} catch (ex){
log(1, "doSomething(): " + ex.message);
}
}
}
2 (Нормальный):
var doSomething = debugMode ?
function(value){
process(value);
} :
function(value){
try {
process(value);
} catch (ex){
log(1, "doSomething(): " + ex.message);
}
};
Второй метод более предпочтительнее, так как он предотвращает проверку дебаг мода каждый раз, когда функция исполняется. Еще его легче автоматизировать. Предполагается, что у вас есть один или несколько обьектов и вы хотите, что бы все их методы имели враппер для отлова ошибок на продакшине. Вот вам пример такого кода:

Пример:
//by Nicholas C. Zakas (MIT Licensed)
function productionize(object){

var name,
method;

for (name in object){
method = object[name];
if (typeof method == "function"){
object[name] = function(name, method){
return function(){
try {
return method.apply(this, arguments);
} catch (ex) {
log(1, name + "(): " + ex.message);
}
};

}(name, method);
}
}
}
Этот код пробегает по всем методам объекта и заменяет его функции на другие, которые уже содержат в себе механизм отлова ошибок. Вот пример использования:
var system = {
fail: function(){
throw new Error("Oops!");
}
};

function log(severity, message){
alert(severity + ":" + message);
}

if (!debugMode){
productionize(system);
}

system.fail(); //error is trapped!
Всегда убеждайтесь в том, что ошибка сгенерировалась именно там где нужно - это первая проблема дебага JS ошибок. Удачи!

По материалам: Nicholas C. Zakas

2 коментарі:

  1. Рецепти коктейлів Рецепти квасів Джек Лондон Зелений Змій Твори Джека Лондона Еміліо Сальгарі Загибель Карфагена Еміліо Сальгарі Місто прокаженого короля Густав Емар Авантюристи Твори Густав Емар Хвороби лабораторні аналізи Стилі архітектури в будівництві Як вибрати проектувальника ландшафту Творчість Томаса Майн Ріда Томас Майн Рід Історія архітектури kapraldr3

    ВідповістиВидалити
  2. Через мозилу никуда не заходит. Пишет javascript error что делать

    ВідповістиВидалити

Що таке база данних?

База данних — це спеціальна система зберігання, організації та пошуку інформації. Вона містить дані у вигляді таблиць, записів та інших стру...