JavaScript try/catch: ошибки или исключения?
ХОРОШО. Я, может быть, и тут раскалываюсь, но мой код не согласован, и я бы хотел, чтобы это было так. Но прежде чем я это сделаю, я хочу убедиться, что я иду по правильному пути. На практике это не имеет значения, но это беспокоило меня некоторое время, поэтому я решил спросить своих коллег...
Каждый раз, когда я использую try... catch
В блоке catch я всегда записываю сообщение на свою внутреннюю консоль. Однако мои сообщения журнала не согласованы. Они либо выглядят так:
catch(err) {
DFTools.console.log("someMethod caught an error: ",err.message);
...
или же:
catch(ex) {
DFTools.console.log("someMethod caught an exception: ",ex.message);
...
Очевидно, что код работает в любом случае правильно, но меня начинает беспокоить то, что я иногда ссылаюсь на "ошибки", а иногда на "исключения". Как я уже сказал, может быть, я расщепляю волосы, но какова правильная терминология? "Исключение" или "Ошибка"?
6 ответов
Это немного субъективно, но для меня ошибка в том, что кто-то или что-то делает что-то не так, неправильно или неправильно. Это может быть синтаксическая ошибка, логическая ошибка, ошибка чтения, ошибка пользователя или даже социальная ошибка. Это абстрактное понятие.
Исключением, с другой стороны, является объект, который создается и генерируется, когда в коде возникает определенное условие. Это может или не может соответствовать концептуальной ошибке. Поэтому для меня правильная номенклатура - это "исключение".
Спецификация ECMAScript вызывает их исключения. Вы можете сделать то же самое.
Чтобы сделать вашу регистрацию более информативной:
catch(ex) {
DFTools.console.log("someMethod caught an exception of type "
+ ex.name + ": ", ex.message);
Вы также можете иметь в виду, что исключения (к сожалению) могут быть любого типа, и поэтому не обязательно имеют name
а также message
свойства:
catch(ex) {
if (ex.message && ex.name) {
DFTools.console.log("someMethod caught an exception of type "
+ ex.name + ": ", ex.message);
} else /* deal with it somehow */
Поскольку это начинает казаться довольно громоздким, чтобы повторяться везде, вы можете захотеть записать его в функцию:
function logExceptions(methodName, action) {
try {
action();
} catch (ex) {
if (ex.message && ex.name) {
DFTools.console.log("someMethod caught an exception of type "
+ ex.name + ": ", ex.message);
} else {
DFTools.console.log("someMethod caught a poorly-typed exception: " + ex);
}
}
}
Теперь вы можете сказать:
logExceptions(function() {
// do some risky stuff...
});
ОСНОВНОЙ ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Я не считаю, что есть "правильный" ответ на этот вопрос. Мнения, высказанные здесь, являются субъективными и личными. Более того, идеи, которые я собираюсь поддержать, полезны только в том случае, если вы собираетесь делать разные вещи с разными, кхм, ошибками... как вы могли бы использовать систему в соответствии с информативным ответом Даниэля Эрвикера. С этим в мыслях:
Я утверждаю, что "ИСКЛЮЧЕНИЕ является исключительным". ОШИБКА менее неожиданна.
отказ от ответственности: следующий псевдокод не годится; это всего лишь минимальный случай, который я мог придумать, чтобы проиллюстрировать мою точку зрения.
примечание: в этом мысленном эксперименте GetFile возвращает UNDEFINED, если не может найти указанный файл.
function AlwaysGetFile(name){
var file = null;
if(FileExists(name)){
file = GetFile(name);
if(typeof file === "undefined"){
throw new "couldn't retrieve file" EXCEPTION
}
}
else{
throw new "file does not exist" ERROR
}
return file;
}
В случае, если потребитель вызывает GetFileOrThrow с несуществующим именем файла, произойдет ОШИБКА. На мой взгляд, на самом деле различие заключается в том, что код более высокого уровня (или пользовательский ввод) делает что-то не так... эта функция должна передать ОШИБКУ вверх по линии к этому высокоуровневому коду, который может решить, что делать с этим результатом. Рассмотрим это так... эта функция будет говорить любым потребляющим функциям:
Послушай, мой друг, я знаю, что здесь происходит: это ОШИБКА, чтобы запросить BobAccounts.xml, так что не делай этого снова! О, и если вы думаете, что теперь знаете, что могло пойти не так (обидев меня), продолжайте и попытайтесь оправиться от этого!
Теперь рассмотрим случай, когда эта функция берет имя, проверяет, существует ли файл, а затем по какой-то причине не может его получить. Это другая ситуация. Произошло нечто действительно неожиданное. Более того, потребительский код не виноват. Теперь мы действительно хотим, чтобы эта функция говорила любым потребляющим функциям:
О, скрипки! Извините за это, я смиренно прошу прощения, но что-то ИСКЛЮЧИТЕЛЬНОЕ, что я действительно не понимаю, пошло не так. Я не думаю, что ваш запрос на BobAccounts.xml был необоснованным... и я знаю, что должен выполнить его для вас. Так как я на более низком уровне кода, чем вы, я действительно должен знать, что происходит... но я не знаю... и, поскольку у вас меньше шансов, чем я, понять эту ИСКЛЮЧИТЕЛЬНУЮ ситуацию, я думаю, что вы, вероятно, Лучше просто перестань делать то, что ты делаешь, и позволь этому сообщению дойти до самого верха... Я имею в виду, что здесь происходит что-то серьезно подозрительное.
Поэтому я полагаю, что мое резюме таково: если ошибка произошла в коде более высокого порядка (вам были переданы неверные данные), выведите ОШИБКУ. Если ошибка произошла в коде более низкого порядка (функция, от которой вы зависели, потерпела неудачу так, как вы не понимали и не могли ее спланировать), выведите EXCEPTION... и если ошибка произошла в функции, которую вы сейчас пишете... ну, ну, если вы знаете об этом, то исправьте это!
И, наконец, чтобы ответить на исходный вопрос более прямо: с точки зрения обработки ОШИБКИ и ИСКЛЮЧЕНИЙ, мой совет был бы: обрабатывать все ОШИБКИ изящно (необязательно регистрируя их)... но действительно обрабатывать ИСКЛЮЧЕНИЯ; только попытайтесь оправиться от ИСКЛЮЧЕНИЯ, если вы действительно уверены, что знаете, что это такое и почему это произошло, в противном случае позвольте этому пузыриться (перебрасывая его, если нужно).
В JavaScript это называется ошибкой отлова. Поэтому я бы предложил вам использовать ошибку вместо исключения. Оставьте выбор посередине, используя "е". Как в примерах Mozilla. Справочник по Mozilla Core JavaScript 1.5
Исключение - это то, что вы можете ожидать, например, при попытке открыть файл может возникнуть ошибка "Файл не найден". С другой стороны, ошибки - это то, что вы можете не увидеть, например, стек по потоку или нехватка памяти.
Исключением является альтернативный логический выход из функции, которая не дает логического результата. Исключение также позволяет лучше объяснить, почему так происходит. Для открытия файла, опять же, дескриптор файла является логическим результатом, и если файл не существует (одно возможное исключение) или это папка, а не файл (другое возможное исключение).
То, что вы получаете в блоке Catch, является исключением, поэтому я называю это исключением...
Если это ошибка - я могу обработать ее в своем коде и обычно не ожидаю увидеть ее в блоке Catch
НТН.