Показ дописів із міткою error. Показати всі дописи
Показ дописів із міткою error. Показати всі дописи

середу, квітня 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

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

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