Javascript: Какой более эффективный блок IF или TRY/CATCH?

Мне нравятся другие мнения о том, что более эффективно в этом коде. В основном в следующем коде есть цикл setInterval, и мне нужно, чтобы 4 требования были истинными до того, как код запустится в цикле. Поэтому в v.1 я написал оператор if, проверяющий все 4. Работал нормально.

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

Либо работает. Мне нравится метод try/catch, потому что там меньше условного кода, который мне нужно написать и беспокоиться о нарушении. Но я волнуюсь, что попытка/улов действительно неэффективна, особенно в цикле setInterval(), достигающем 100 мс. Каковы некоторые мнения о других ярких умах здесь, на SO?

Try/Поймать

var intvar = setInterval(function(){
try{    
    clearInterval(intvar);

    jQuery('#'+nav[pageid].t1+'>a').replaceWith(jQuery('<span>'+jQuery('#'+nav[pageid].t1+'>a').text()+'</span>'));

    //set display classes for nav
    jQuery('#'+nav[pageid].t1).addClass('selected').find('#'+nav[pageid].t2).addClass('subselect'); //topnav
    jQuery('#'+nav[pageid].t3).addClass('selected').find('#'+nav[pageid].t4).addClass('subselect'); //leftnav
}catch(err){}
},100);

Блок IF

var intvar = setInterval(function(){

if(typeof jQuery == 'function' && typeof nav == 'object' && typeof pageid != 'undefined' && typeof document.getElementById('leftnav') == 'object'){
    clearInterval(intvar);
    jQuery('#'+nav[pageid].t1+'>a').replaceWith(jQuery('<span>'+jQuery('#'+nav[pageid].t1+'>a').text()+'</span>'));

    //set display classes for nav
    jQuery('#'+nav[pageid].t1).addClass('selected').find('#'+nav[pageid].t2).addClass('subselect'); //topnav
    jQuery('#'+nav[pageid].t3).addClass('selected').find('#'+nav[pageid].t4).addClass('subselect'); //leftnav
}

},100);

Ответы

Ответ 1

Используйте оператор if. Я не знаю, что накладные расходы для TRY/CATCH, но я подозреваю, что это намного больше, чем оценка булевского выражения. Чтобы попасть в TRY/CATCH, вам необходимо: выполнить инструкцию, сгенерировать ошибку [с этими связанными служебными данными], занести в журнал ошибку (предположительно), сделать stacktrace (предположительно) и вернуться в код. Кроме того, если вам нужно отлаживать код рядом с этими строками, реальная ошибка может быть запутана тем, что вы TRY/CATCHing.

Кроме того, это неправильное использование TRY/CATCH и может сделать ваш код намного труднее для чтения. Предположим, вы делаете это для более длинных или более запутанных случаев? Где может быть ваш захват?

Это называется Обработка исключений

РЕДАКТИРОВАТЬ: Как указано ниже, вы принимаете только производительность выполнения, если вы действительно вызываете исключение.

Ответ 2

Исключения должны использоваться для исключительных обстоятельств (т.е. вещей, которые вы не ожидаете обычно). Вы не должны, в общем, использовать исключения, чтобы поймать что-то, что вы можете проверить с помощью оператора if.

Кроме того, из того, что я понимаю, исключения намного дороже, чем заявления.

Ответ 3

Другие ответы верны, try/catch - для исключительных ситуаций и обработки ошибок. if условия для логики программы. "Что быстрее?" это неправильный вопрос.

Хорошее эмпирическое правило, если вы ничего не делаете с исключением, это, вероятно, не исключение!

Чтобы выяснить, что использовать, давайте сломаем ваше условие if.

  • typeof jQuery == 'function' Определяется ли функция jQuery()?
  • typeof nav == 'object' Поддерживает ли глобальная переменная nav объект?
  • typeof pageid != 'undefined' Определена ли глобальная переменная pageid?
  • typeof document.getElementById('leftnav') == 'object' В документе содержится элемент leftnav?

Первое, безусловно, является исключением. Вы не получаете далеко без функции jQuery().

Вторая также является исключением. Вы не идете никуда, кроме навигационного объекта.

Третий - это исключение. Чтобы сделать что-нибудь, вам понадобится pageid.

Четвертый, вероятно, логический. "Запускайте этот код только в том случае, если есть элемент leftnav". Трудно сказать, потому что остальная часть кода не ссылается на элемент leftnav! Только комментарии делают, красный флаг. Так что это, вероятно, ошибка программирования.

Поэтому я, вероятно, сделаю это (с извинениями, если я разбойник jQuery):

var intvar = setInterval(function() {
    // If there no leftnav element, don't do anything.
    if( typeof document.getElementById('leftnav') != 'object') {
        return;
    }

    try {
        clearInterval(intvar);
        jQuery('#'+nav[pageid].t1+'>a')
            .replaceWith(jQuery('<span>'+jQuery('#'+nav[pageid].t1+'>a').text()+'</span>'));

        //set display classes for nav
        jQuery('#'+nav[pageid].t1)
            .addClass('selected')
            .find('#'+nav[pageid].t2)
            .addClass('subselect');     //topnav
        jQuery('#'+nav[pageid].t3)
            .addClass('selected')
            .find('#'+nav[pageid].t4)
            .addClass('subselect');     //leftnav
    }
    catch(err) {
        ...do something with the error...
    }
},100);

... но я действительно проверял, применима ли проверка элемента leftnav.

Наконец, я не могу не отметить, что эта "функция" работает с глобальными переменными. Вместо этого вы должны передавать nav и pageid в функцию, чтобы поддерживать инкапсуляцию и разумность.

Ответ 4

Я бы написал следующий код:

var startTime = (new Date()).getTime();
for (var i=0; i < 1000; ++i) intvar();
var endTime = (new Date()).getTime();
alert("Took " + ((endTime - startTime) / 1000.0) " seconds");

Затем я попробую обе версии intvar и посмотрю, что работает быстрее. Я бы сделал это сам, но у меня нет макета страницы, который вы делаете, чтобы мой код не работал.

Некоторые стилистические комментарии - нет необходимости проверять, что jQuery - это функция. Если это не так, ваша веб-страница, скорее всего, будет испорчена, так что не запускать код intvar вам не поможет. Если вы редко ожидаете, что будут исключены исключения, я бы использовал try/catch.

Ответ 5

В приведенном примере, где вы обертываете try/catch вокруг блока кода, который должен всегда запускаться в любом случае (если только не произойдет что-то ужасное), это хорошая форма использования try/catch. Аналогия для вас: вы всегда проверяете "Является ли небо голубым?" в вашем операторе if, или вы можете обернуть его в try/catch, который запускается только тогда, когда небо превратится в зеленый цвет.

Используйте метод if if, если вы имеете дело с введенным пользователем вводом или если вероятность отсутствия функции намного выше из-за чего-то еще, происходящего в коде.

Имейте в виду, что если вы не инициируете исключение, у вас нет разматывания или возврата по коду. В примере catch будет выполняться только в том случае, если что-то не так (jQuery отсутствует или какая-то такая вещь), однако метод if-if имеет оценку, выполняемую на КАЖДОЙ ОДИНОЧНОЙ ВЫЗОВЕ этой функции - вы не должны делать больше работы, чем вам нужно.

Ответ 6

Чтобы ответить на вопрос, как и все остальные, try..catch, вероятно, будет дороже, если на самом деле есть ошибка.

Чтобы указать дополнительные ошибки в коде, за исключением того, что уже указывали другие:

Эти два кода вовсе не эквивалентны. Чтобы объяснить, хотя коды, похоже, делают то же самое, они этого не делают.

В случае проверки if() выполняется NONE кода. В случае обработчика исключений каждая строка кода внутри обработчика исключений будет выполнена. SO, что произойдет, если ошибка возникает во второй или третьей строке? Тогда у вас есть что-то совершенно другое в вашем коде, чем то, что вы получаете, если вы проверяете условия, прежде чем выполнять какие-либо из них.

Ответ 7

Помимо приведенных ответов, я хочу добавить некоторые мысли по этому вопросу.

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

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

Например, у вас может быть метод, который проверяет пользовательский ввод, чтобы вы могли иметь метод isValid который возвращает логическое значение, и в этом случае вы бы использовали if... then.

С другой стороны, если вы выполняете определенный процесс и знаете, что может возникнуть определенное исключение, которое прерывает счастливый поток, и вы хотите с этим справиться, я чувствую, что лучше создать исключение.

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

throw new BusinessValidationException(TAG, 'Reason for the validation');

Какой ИМО гораздо более описательный, чем:

if (!checkValidityBusinessRule()) 
    // doSomething 

Для серии бизнес-правил.

Что касается примера, это мое скромное мнение, что эта проверка не должна происходить в первую очередь, и что эти проверки являются истинными по умолчанию для реализации метода.

if(typeof jQuery == 'function' && typeof nav == 'object' && typeof pageid != 'undefined' && typeof document.getElementById('leftnav') == 'object')

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

Мои 2 цента, я надеюсь, что они имеют смысл.