попробуй поймай в javascript… разве это не хорошая практика?


69

В javascript есть условие для блока try-catch . В то время как в java или любом другом языке обязательно иметь обработку ошибок, я не вижу, чтобы кто-нибудь использовал их в javascript для большей степени. Разве это не хорошая практика или просто мы не нуждаемся в них в javascript?


2
While in java or *any other language* it is mandatory to have error handling...- На самом деле, нет. Java, да, но есть много языков, которые не настаивают на try-catch (например, C #).
Джим Г.

Это потому, что вы не можете использовать их в асинхронной среде. Я часто использую их для синхронизации кода с более низким уровнем абстракции, например, путем преобразования чего-либо во что-то и т. Д.
inf3rno

Держу пари, вы видите больше try-catch в коде на стороне сервера, чем на стороне клиента. Большая часть кода на стороне клиента, к которому вы имеете отношение, ничего не делает. Я бы поспорил, что свести к минимуму КБ по конвейеру важнее, чем восстановление после каждой ошибки - в большинстве приложений и на стороне браузера.
svidgen

Есть еще один способ избежать попытки отлова с использованием возможно и Either (монад), у нас был записан веб-скребок в node. Мы смогли удалить все попытки поймать, используя его.
user93

Ответы:


66

Следует избегать throwошибок как способа передачи условий ошибок в приложениях.

throwЗаявление должно быть использовано только «Для этого не должно произойти, аварии и сжечь. Не восстанавливайте элегантно в любом случае»

try catch однако используется в ситуации, когда хост-объекты или ECMAScript могут выдавать ошибки.

Пример:

var json
try {
    json = JSON.parse(input)
} catch (e) {
    // invalid json input, set to null
    json = null
}

В сообществе node.js рекомендуется, чтобы вы передавали ошибки в обратных вызовах (поскольку ошибки возникают только для асинхронных операций) в качестве первого аргумента.

fs.readFile(uri, function (err, fileData) {
    if (err) {
        // handle
        // A. give the error to someone else
        return callback(err)
        // B. recover logic
        return recoverElegantly(err)
        // C. Crash and burn
        throw err
    }
    // success case, handle nicely
})

Есть и другие проблемы, такие как try / catch очень дорого, уродливо и просто не работает с асинхронными операциями.

Так как синхронные операции не должны выдавать ошибку и не работают с асинхронными операциями, никто не использует try catch, кроме ошибок, генерируемых объектами хоста или ECMAScript


2
Я бы не сказал, что никто не использует try catch, в большинстве случаев это просто неправильный инструмент для работы. Когда есть действительно исключительные обстоятельства, стоит бросить Error, но их мало и далеко.
zzzzBov

7
@zzzzBov Нет ничего плохого в том, чтобы выдавать ошибки для случая C, сбой и запись. Я просто не думаю, что вы должны ловить ошибки и восстанавливаться. Например document.getElementById, не выбрасывает, когда элемент не существует, он просто возвращает null. То же самое можно сделать почти во всех случаях
Raynos

4
@Raynos, бросание из функции синхронизации полностью приемлемо и имеет смысл в этом случае использования. Возврат ошибки в функцию обратного вызова выполняется в асинхронном режиме, так как ошибка в процессе синхронизации должна синхронизироваться.
sbartell

У @Raynos есть хороший совет, как избегать использования ошибок / исключений для управления потоком на стороне клиента (не в среде Node)? Я нашел этот пост в StackOverflow , но он в основном ориентирован на Java
blong

@ b.long просто. не бросайте ошибки никогда. Задача решена.
Raynos

32

Try / catch в Javascript не так пуленепробиваем, как в других языках, из-за асинхронной природы Javascript. Рассмотрим этот фрагмент:

try {
    setTimeout(function() {
        do_something_that_throws();
    }, 1000);
}
catch (e) {
    alert("You won't see this!");
}

Проблема заключается в том, что поток управления покидает tryблок до того, как do_something_that_throws()будет выполнен, поэтому ошибка, генерируемая внутри обратного вызова, никогда не перехватывается.

Так что try / catch в принципе неуместен во многих случаях, и не всегда очевидно, выполняет ли что-то код асинхронно или нет. К счастью, javascript с его особой идиомой однопоточного асинхронного обратного вызова и его поддержкой фактических замыканий предоставляет элегантную альтернативу: обработка ошибок в стиле продолжения передачи. Просто передайте правильный ответ на любую ошибку как функцию, например:

setTimeout(function () {
    do_something_that_calls_err(function(err) {
        alert("Something went wrong, namely this: " + err);
    }),
    1000);

5
это не пуленепробиваемый на других языках. Перенесите этот код на любой язык, который поддерживает асинхронные обратные вызовы, и он тоже потерпит неудачу.
Raynos

2
@Raynos: Вы правы; однако, другие языки (или, скорее, их поддерживающие культуры) не покупают это в значительной степени в идиоме асинхронного обратного вызова, как Javascript, и из-за многопоточной природы большинства других сред недостатки try / catch более очевидны и окруженный множеством других предостережений, поэтому люди, естественно, осторожно ходят в многопоточных / асинхронных ситуациях обратного вызова и больше осведомлены о потенциальных ловушках.
tdammers

Это действительно из-за «асинхронной природы» JavaScript? Насколько я вижу, Try / Catch теоретически можно заставить работать лексически, например, как идентификаторы лексически закрыты; просто так не бывает в JavaScript.
Брайан Гордон

2
В node.js> = 0.8 стоит отметить, что можно пытаться / ловить асинхронно, см. Мой вопрос stackoverflow.com/questions/14301839/…
Бенджамин Грюнбаум

Является ли единственной альтернативой синхронному try-catch стиль передачи асинхронного продолжения?
CMCDragonkai

23

Многие из этих ответов устарели asyncи не учитывают новые функции ES7 и await.

Используя async/ awaitвы можете теперь получить асинхронный поток управления, как вы хотите:

async function email(address) {
  try {
    // Do something asynchronous that may throw...
    await sendEmail({ to: address, from: 'noreply@domain.com`, subject: 'Hello' })
  } catch(err) {
    if (err instanceof SomeCustomError) {
      elegantlyHandleError(err)
    } else {
      throw err
    } 
  }
})

Узнайте больше о async/ awaitздесь . Вы можете использовать async/ awaitсейчас, используя Babel .


Но это похоже на синхронный код
Атул Агравал

@AtulAgrawal да, в этом все дело. Async / await позволяет вам писать асинхронный код в синхронном стиле, чтобы вы могли избежать «ада обратного вызова» и связать воедино множество обещаний. По моему мнению, это очень приятный способ написать асинхронный код
Дана Вудман,

Так в чем же преимущество использования javascript, если мы делаем асинхронный код синхронным. потому что большинство людей используют javascript из-за его асинхронной природы
Атул Агравал

2
@AtulAgrawal вы получаете лучшее из обоих миров - вы наслаждаетесь асинхронной природой языка (так как приведенный выше код будет по-прежнему выполняться асинхронно - освобождая поток и все) и пользуетесь преимуществами более удобного для программистов стиля кодирования. Это не без проблем, однако ...
ZenMaster

15

try-catch в javascript так же действителен и полезен, как и в любом другом языке, который их реализует. Есть одна главная причина, по которой он не используется в javascript так часто, как в других языках. По той же причине javascript считается уродливым скриптовым языком, по той же причине, по которой люди думают, что программисты на javascript не являются настоящими программистами:

  • Javascript - это невероятно доступный и распространенный язык

Сам факт того, что так много людей подвергаются воздействию javascript (благодаря тому, что браузеры поддерживают только поддерживаемый язык), означает, что у вас есть много непрофессионального кода. Конечно, есть также много незначительных причин:

  • некоторые вещи в JavaScript являются асинхронными и, следовательно, не catchмогут (асинхронные вещи)
  • было много преувеличенных разговоров о том, что try-catch имеет огромный удар по производительности. Это немного снижает производительность , но для большинства кода оно того стоит.
  • javascript (к сожалению) был реализован таким образом, что он часто игнорирует ошибки (например, автоматически изменяя строки на числа)

В любом случае, следует использовать try-catch , но, конечно, вы должны научиться правильно их использовать - как и все остальное в программировании.


3
И почему ты когда-нибудь понижал голос, о тихий даунотер?
user250878

Согласовано. Я думаю, что принятый ответ в целом верен, но есть веские причины использовать try-catch и даже throw, кроме случаев, когда имеешь дело с нативными объектами. Когда ошибка вызывается, а не передается обратному вызову, она останавливает дальнейшее выполнение и поднимает стек до первого блока, чем может его обработать. Это большое преимущество и имеет смысл для синхронных операций, особенно если они включают в себя глубокое вложение. Кажется безумным предполагать, что исключения являются «плохими» (ну, кроме как по очевидным причинам) - они на самом деле очень полезный инструмент с уникальной «мощью».
точка с запятой

2
Вы когда-нибудь читали исходный код, скажем, jQuery? Вряд ли есть какая-либо попытка поймать, за исключением тех сценариев, которые упомянуты в принятом ответе: обнаруживать особенности и использовать собственные / хост-объекты, которые выдают ошибки. Называть код, который не использует try-catch (например, jQuery) «непрофессионально», кажется глупым. Честно говоря, я думаю, что это особенно новые программисты Javascript, пришедшие из Java, которые склонны переусердствовать с такими языковыми функциями, как try-catch.
Стейн де Витт

6

Я полагаю, что большая часть причины, которая try..catchредко встречается в JavaScript, заключается в том, что язык имеет довольно высокую устойчивость к ошибкам. Подавляющее большинство ситуаций может быть обработано с помощью проверок кода, правильных значений по умолчанию и асинхронных событий. В некоторых случаях простое использование шаблона предотвратит проблемы:

function Foo() {
    //this may or may not be called as a constructor!!
    //could accidentally overwrite properties on window
}

function Bar() {
    if (!(this instanceof Bar)) {
        return new Bar();
    }
    //this will only work on Bar objects, and wont impact window
}

Некоторые из основных проблем в других языках, которые вызывают исключения, просто не существуют в JS. В большинстве случаев кастинг не требуется. Вместо этого предпочтительным методом обычно является проверка функций (принудительное использование определенного интерфейса):

function doFoo(arg) {
    if (arg.foo) {
        arg.foo();
    } else {
        Bar.prototype.foo.call(arg);
    }
}

С добавлением async/ awaitк языку try..catchстановится все более распространенным. Обещания, являющиеся асинхронной формой try..catch, имеют смысл ожидать:

doSomething().then(
  doSomethingWithResult,
  doSomethingWithError
)

вместо этого быть написано как:

try {
  const result = await doSomething()
  doSomethingWithResult(result)
} catch (e) {
  doSomethingWithError(e)
}

3

Возможно, еще одна причина, по которой try / catch не очень часто используется в Javascript, заключается в том, что конструкция не была доступна в самых первых версиях Javascript ... она была добавлена ​​позже.

В результате некоторые старые браузеры не поддерживают его. (На самом деле, это может вызвать синтаксическую / синтаксическую ошибку в некоторых старых браузерах, что более сложно «защищать» от большинства других типов ошибок.)

Что еще более важно, поскольку он изначально не был доступен, встроенные функции Javascript, которые были первоначально выпущены (то, что на многих языках называлось бы «библиотечными» функциями), не используют его. (Он не очень хорошо «ловит» ошибку от someobject.somefunction (), если он не «выбрасывает», а вместо этого просто возвращает «ноль» при возникновении проблемы.)


Еще одной возможной причиной является то, что механизм try / catch изначально не казался необходимым (и все же он не кажется таким уж полезным). Это действительно необходимо, только когда вызовы обычно вложены в несколько уровней; простое возвращение какого-либо типа ERRNO прекрасно подойдет для прямых вызовов (хотя, чтобы сделать его действительно полезным, когда он доступен, в большинстве языков рекомендуется использовать его везде, а не только при глубоко вложенных вызовах). Поскольку изначально логика Javascript должна была быть небольшой и простой (в конце концов, это просто дополнение к веб-странице :-), не ожидалось, что вызовы функций будут глубоко вложенными, и поэтому механизм try / catch не кажется необходимым.


3
Нет, нет, абсолютно не так. Старые движки больше не имеют значения в течение длительного времени, и сообщество javascript в целом быстро отбрасывает старые вещи, когда это оправдано. Я бы даже поспорил, что большинство разработчиков javascript сейчас работают после IE6.
Камило Мартин

0

Я полагаю, что они не используются так часто, потому что выбрасывание исключений в клиентском коде Javascript затрудняет отладку страницы.

Вместо того , чтобы бросать исключения, я обычно предпочитаю , чтобы показать окно предупреждения аль (то есть alert("Error, invalid...");)

Это может показаться странным, но ошибки Javascript случаются на стороне клиента, если клиент использует созданную вами страницу, и страница выдает исключение, если только клиент не разбирается в технических знаниях, он никак не сможет сказать, Вы в чем проблема.

Он только позвонит вам и скажет: «Эй, страница X не работает!», И тогда вам остается только выяснить, что пошло не так и где в коде.

Используя вместо этого окно с предупреждением, более вероятно, что он звонит и говорит что-то вроде: «Эй, когда я нажимаю на кнопку A на странице X, появляется окно с надписью ...» , поверьте мне, это будет намного легче найти баг.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.