Почему возврат в `finally` отменяет` try`?

100

Как работает оператор return внутри блока try / catch?

function example() {
    try {
        return true;
    }
    finally {
        return false;
    }
}

Я ожидаю, что результат этой функции будет true, но вместо этого он есть false!

бонфо
источник
Для других возвращайте false в блоке catch, а не в final.
Хабибхассани

Ответы:

95

Наконец, всегда выполняется. Это то, для чего он нужен, а это значит, что в вашем случае используется return.

Вы захотите изменить свой код, чтобы он выглядел примерно так:

function example() { 
    var returnState = false; // initialisation value is really up to the design
    try { 
        returnState = true; 
    } 
    catch {
        returnState = false;
    }
    finally { 
        return returnState; 
    } 
} 

Вообще говоря, вы никогда не захотите иметь более одного оператора return в функции, вот почему.

аннаката
источник
47
Я бы сказал, что наличие более одного оператора возврата не всегда плохо - см. Stackoverflow.com/questions/36707/… для более подробного обсуждения.
Кастрохендж
5
Я тоже не согласен с правилом одного возврата. Однако вы никогда не должны возвращаться из finally (в C # это даже не разрешено).
erikkallen 01
@erikkallen - это хороший аргумент. Лучше всего будет возврат за пределы блока TCF, но пример кода будет немного принудительным :)
annakata 01
1
@Castrohenge - это не жесткое и быстрое правило, но большинство примеров-копунтеров в этом потоке довольно надуманы, и единственный допустимый случай, который я вижу, - это «условие защиты» (по сути, шаблон проверки входных данных в верхней части функция и возврат условно). Это вполне допустимый случай, но на самом деле эти возвраты должны быть исключениями (опять же, не жестко и быстро).
annakata
1
На самом деле в IE6 и IE7, наконец, не всегда выполняется во всех случаях из-за довольно серьезной ошибки браузера. В частности, если исключение выбрасывается в блоке try-finally, который не окружен более высоким уровнем try-catch, то блок finally не будет выполняться. Вот тестовый пример jsfiddle.net/niallsmart/aFjKq . Эта проблема была исправлена ​​в IE8.
Niall Smart
44

Согласно ECMA-262 (5ed, декабрь 2009 г.), на стр. 96:

Производство TryStatement : try Block Finallyоценивается следующим образом:

  1. Пусть B будет результатом вычисления Block.
  2. Пусть F будет результатом вычисления finally.
  3. Если F.type нормальный, верните B.
  4. Возврат F.

И со стр.36:

Тип Завершение используется для объяснения поведения операторов ( break, continue, returnи throw) , которые выполняют нелокальные передачу управления. Значения типа завершения являются триплеты вида (тип, значение, цель) , где тип является одним из normal, break, continue, return, или throw, значение любое значение ECMAScript языка или пустой, и целевой любой идентификатор ECMAScript или пуст.

Очевидно , что return falseбы установить тип завершения в конце концов , как возвращение , что вызывает try ... finallyделать 4. Возвращение F .

ливибеттер
источник
2
После прочтения всевозможных «в основном правильных, но в некотором роде мягких и не проясняющих» ответов на этот вопрос этот вопрос действительно обрел смысл. Ключевым моментом было то, что все, что «происходит» в конце try + catch (return или throw или просто нормальный поток), запоминается, пока выполняется часть finally, а затем фактически происходит только в том случае, если в конце finally ничего не происходит.
PreventRage
14

При использовании finallyлюбой код в этом блоке срабатывает до выхода из метода. Поскольку вы используете возврат в finallyблоке, он вызывает return falseи отменяет предыдущий return trueв tryблоке.

(Терминология может быть не совсем правильной.)

djdd87
источник
4

Перезапись блока finally пытается вернуть блок (образно говоря).

Просто хотел указать, что если вы вернете что-то из finally, то оно будет возвращено из функции. Но если в finally нет слова return - будет возвращено значение из блока try;

function example() {
    try {
        return true;
    }
    finally {
       console.log('finally')
    }
}
console.log(example());
// -> finally
// -> true

Итак, -finally- returnперезаписывает возврат -try- return.

Михей Мик
источник
3

почему вы получаете false, вы вернулись в блоке finally. блок finally должен выполняться всегда. так что ваши return trueизменения вreturn false

function example() {
    try {
        return true;
    }
    catch {
        return false;
    }
}
аниш
источник
1

Насколько мне известно, finallyблок выполняется всегда , независимо от того, есть ли у вас returnвнутри оператор tryили нет. Итак, вы получаете значение, возвращаемое returnоператором внутри блока finally.

Я тестировал это с Firefox 3.6.10 и Chrome 6.0.472.63 как в Ubuntu. Возможно, что этот код может вести себя иначе в других браузерах.

Манодж Говиндан
источник
1

Возвращение из блока finally

Если finally-block возвращает значение, это значение становится возвращаемым значением всего try-catch-finallyоператора, независимо от любых returnоператоров в tryи catch-blocks

Ссылка: developer.mozilla.org

То
источник
1

Я дам здесь немного другой ответ: да, оба блока tryи finallyвыполняются и finallyимеют приоритет над фактическим "возвращаемым" значением для функции. Однако эти возвращаемые значения не всегда используются в вашем коде.

Вот почему:

  • В приведенном ниже примере будет использоваться res.send()файл из Express.js, который создает и отправляет HTTP-ответ.
  • Ваш tryи finallyблок будет одновременно выполнять эту функцию следующим образом:
try {
    // Get DB records etc.
    return res.send('try');
} catch(e) {
    // log errors
} finally {
    return res.send('finally');
}

Этот код покажет строку tryв вашем браузере. ТАКЖЕ, пример покажет ошибку в вашей консоли. res.send()Функция вызывается дважды . Это произойдет со всем, что является функцией. Блок try-catch-finally скрывает этот факт от неподготовленного глаза, потому что (лично) я связываю returnзначения только с областями действия.

Имхо, лучше всего никогда не использовать returnвнутри finallyблока . Это усложнит ваш код и потенциально замаскирует ошибки.

Фактически, в PHPStorm есть настройка правила проверки кода по умолчанию, которая выдает «Предупреждение» для этого:

https://www.jetbrains.com/help/phpstorm/javascript-and-typescript-return-inside-finally-block.html

Итак, для чего вы используете finally?

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

Это может иметь смысл, если вы подумаете об этом, потому что, когда вы зависите от строки кода ниже finally, вы предполагаете, что могут быть ошибки в tryили catch. Но эти последние 2 - фактические строительные блоки обработки ошибок. Просто используйте вместо него returnin tryи catch.

Пламя
источник
-2

Наконец, предполагается, что ВСЕГДА запускается в конце блока try catch, поэтому (по спецификации) именно поэтому вы получаете false. Имейте в виду, что вполне возможно, что разные браузеры имеют разные реализации.

Darko Z
источник
IE8, Firefox 3.6 и Chrome 6: все одинаковы;)
bonfo 01
-3

Как насчет этого?

doubleReturn();

function doubleReturn() {
  let sex = 'boy';

  try {
    return sex;

    console.log('this never gets called...');
  } catch (e) {} finally {
    sex = 'girl'; 

    alert(sex);
  }
}
Томас Карлссон
источник