Добавлен ScorpioT1000,
опубликован
Раздел:
Общее
Хотел бы рассказать и обсудить различные способы обработки ошибок и исключительных ситуаций в современной разработке в стиле статьи + комментарии.
Буду использовать Javascript как наиболее популярный. Для нешарящих, слово function может быть объявлением класса в случае создания её свойств.
Буду использовать Javascript как наиболее популярный. Для нешарящих, слово function может быть объявлением класса в случае создания её свойств.
Я помню всего шесть способов обработки ошибок в программировании, но хочу обратить внимание на последние четыре.
Возврат значения
Довольно бородатый и устаревший способ - просто возвращать null или любое значение, которое означает ошибку. Распространено из Linux API.
/** @return int -1 if negative, 0 if zero */
function doSomething(i) {
if(i < 0) {
return -1;
} else if(i == 0) {
return 0;
}
return i*i + 5;
}
var result = doSomething(x);
switch(result) {
case -1: // ... negative
case 0: // ... zero
default: // ... success
}
Преимущества: Очень быстро и очень легко написать
Недостатки: Ошибку нельзя проверить "потом", много условий, ошибки приходится описывать в документации, возвращаемые значения по диапазону.
Недостатки: Ошибку нельзя проверить "потом", много условий, ошибки приходится описывать в документации, возвращаемые значения по диапазону.
GetLastError()
Тоже довольно бородатый, но всё ещё используемый способ обработки ошибок - обращение к менеджеру объектов. Распространено из Windows API.
Допустим, есть менеджер manager и объект obj.
function Manager() {
var me = this;
me.lastError = '';
me.getLastError = function() { return me.lastError; }
me.doSomething1 = function(whichObj) {
me.lastError = '';
if(! whichObj) {
me.lastError = 'object is null';
}
// ... do something and return something
}
me.doSomething2 = function(whichObj) {
me.lastError = '';
if(! whichObj) {
me.lastError = 'object is null';
}
// ... do something 2 and return something 2
}
}
var manager = new Manager();
var obj = new Obj();
manager.doSomething1(obj);
manager.doSomething2(obj);
// ...
if(manager.getLastError() == 'object is null') {
console.log("Объект "+obj.name+" пуст.");
}
Преимущества: Ошибку в некоторых случаях можно не проверять сразу, значения довольно интуитивные и не затрагивают возвращаемые значения.
Недостатки: В некоторых случаях всё ещё не понятно, почему функция не выполнилась, для каждого родительского класса свой менеджер (при правильном проектировании), что ведет к создании родительского менеджера-обработчика всех ошибок, много мета-информации.
Недостатки: В некоторых случаях всё ещё не понятно, почему функция не выполнилась, для каждого родительского класса свой менеджер (при правильном проектировании), что ведет к создании родительского менеджера-обработчика всех ошибок, много мета-информации.
Exceptions
Исключения. Почти все мы знакомы с ними... Исключение - сигнал, указывающий на возникновение какой-либо исключительной ситуации или ошибки.
function doSomething1(input) {
// ...
throw new Error('wrong input');
// ...
}
function doSomething2(data) {
// ...
throw new Error('wrong data');
// ...
}
try {
doSomething2(doSomething1(myInput));
} catch(e) {
console.log(e.message);
}
Преимущества: Контроль за всеми возможными ошибками почти в произвольном месте потока, интуитивные значения, кроме значений можно передавать другие параметры отладки (в том числе колл-стек), ни коим образом не мешают логике при не-исключительных ситуациях, могут быть использованы не только для обработки ошибок, но и для других "скачков" по потоку (например, мгновенный выход и многоуровневого цикла).
Недостатки: Некоторые языки требуют обрабатывать все возможные исключения, проблемы с асинхронностью на разных языках, всё ещё не до конца решена проблема нулевых указателей (особенно в случае работы со сторонними библиотеками, ведь нулл - не всегда плохо).
Недостатки: Некоторые языки требуют обрабатывать все возможные исключения, проблемы с асинхронностью на разных языках, всё ещё не до конца решена проблема нулевых указателей (особенно в случае работы со сторонними библиотеками, ведь нулл - не всегда плохо).
Handlers
Относительно часто используемый механизм обработки ошибок - разделение потоков выполнения. Получил свою популярность с приходом понятия замыкание.
Суть обработчиков - обрывать текущий поток (в некоторых решениях - не обрывать в случае успеха) и выполнять один из двух новых - случай ошибки и случай успеха. Распространено в javascript библиотеках вроде jQuery, а так же в Nodejs
function doSomething(input, onSuccess, onFail) {
// ...
onSuccess && onSuccess(result);
// ...
onFail && onFail(error);
}
var input = 'my input';
doSomething(
input,
function(result) {
console.log('success: ' + result);
},
function(error) {
console.log('error:' + error);
}
);
Преимущества: Контроль за всеми возможными ошибками, интуитивные значения, асинхронная работа (в конкретных случаях), передача любых параметров, могут быть использованы не только для обработки ошибок, но и для обработки вообще любых ситуаций.
Недостатки: В компилируемых языках приходится писать специальные механизмы для такого рода обработок, в больших проектах - трудно уследить за потоком выполнения, особенно в случае анонимных функций. Проблема "лесенок" или Callback Hell.
Недостатки: В компилируемых языках приходится писать специальные механизмы для такого рода обработок, в больших проектах - трудно уследить за потоком выполнения, особенно в случае анонимных функций. Проблема "лесенок" или Callback Hell.
Promise
Объект Promise (обещание) используется для отложенных и асинхронных вычислений. Promise может находиться в трёх состояниях:
- ожидание (pending): начальное состояние, не выполнено и не отклонено.
- выполнено (fulfilled): операция завершена успешно.
- отклонено (rejected): операция завершена с ошибкой.
var promise = new Promise(function(resolve, reject) {
// здесь вытворяй что угодно, если хочешь асинхронно, потом…
if (/* ..если всё закончилось успехом */) {
resolve("Работает!");
}
else {
reject(Error("Сломалось"));
}
});
promise.then(function(result) {
console.log(result); // "Обрабатываем результат!"
}, function(err) {
console.log(err); // Ошибка: "Сломалось"
});
Преимущества: Контроль за всеми возможными ошибками, интуитивные значения, асинхронная работа (в конкретных случаях), передача любых параметров, могут быть использованы не только для обработки ошибок, но и для обработки вообще любых ситуаций, проверка над множествами случаев или некоторыми случаями в одном месте.
Недостатки: Реализовано далеко не во всех языках, Не подходит для повторяющихся событий, Не подходит для streams, Текущая реализация в браузерах не позволяет следит за progress
Недостатки: Реализовано далеко не во всех языках, Не подходит для повторяющихся событий, Не подходит для streams, Текущая реализация в браузерах не позволяет следит за progress
Null Object
Null Object - это объект с определенным нейтральным («null») поведением. Началось всё с книг, так же я лично замечал это в MFC с состояниями isEmpty у многих объектов, кроме того, это распространено в C++ iostream.
Лично я вижу это приблизительно так:
function NullObject() {
var me = this;
me._error = '';
me.isBad = function() { return !!me._errror; }
me.isGood = function() { return !me._error; }
me.getError = function() { return me._error; }
me.setError = function(e) { me._error = e; }
}
function MyClass() { // extends NullObject
var me = this;
angular.extend(me, new NullObject()); // или любая функция наследования
// fields
// ...
// methods
me.doSomething1 = function() {
if(me.isBad()) { return me; }
// ...
me.setError('wrong vodka');
return me;
}
me.doSomething2 = function() {
if(me.isBad()) { return me; }
// ...
me.setError('wrong beer');
return me;
}
}
var obj = new MyClass();
obj.doSomething1().doSomething2().doSomething1();
if(obj.isBad()) {
console.log(obj.getError());
}
Преимущества: Контроль за всеми возможными ошибками, интуитивные значения, передача любых параметров (если задано в родителе), могут быть использованы не только для обработки ошибок, но и для обработки вообще любых ситуаций, реализуемо в любых ООП языках, последовательное выполнение методов без остановки потока.
Недостатки: Синхронность, нужно писать некоторые проверки в требуемых методах, нет работы с множеством случаев, требуется перестраивать дерево наследования, дополнительные данные в объектах.
Недостатки: Синхронность, нужно писать некоторые проверки в требуемых методах, нет работы с множеством случаев, требуется перестраивать дерево наследования, дополнительные данные в объектах.
Заключение
Какие ещё вы знаете способы обработки ошибок и где они могут применяться?
`
ОЖИДАНИЕ РЕКЛАМЫ...
Чтобы оставить комментарий, пожалуйста, войдите на сайт.
Отредактирован AsagiriGen
Их преимущество - ориентированы не только на обработку программных ошибок, но и аппаратных. И выражение-фильтр опять же.
_try
{
_try
{
........
}
_except(выражение-фильтр)
{
.........
{
}
_except(выражение фильтр)