Por que um retorno em `finally` substitui` try`?

94

Como funciona uma instrução return dentro de um bloco try / catch?

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

Estou esperando que a saída dessa função seja true, mas, em vez disso, é false!

bonfo
fonte
Para outros, faça o retorno falso no bloco catch, não finalmente.
habibhassani,

Respostas:

91

Finalmente sempre executa. É para isso que serve, o que significa que seu retorno é usado no seu caso.

Você vai querer mudar seu código para que fique mais parecido com isto:

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

De modo geral, você nunca quer ter mais de uma instrução de retorno em uma função, coisas como essas são o motivo.

Annakata
fonte
45
Eu diria que ter mais de uma instrução de retorno nem sempre é ruim - consulte stackoverflow.com/questions/36707/… para mais discussão.
Castrohenge,
5
Eu também discordo sobre a regra de retorno único. Porém, você nunca deve retornar de finalmente (em C #, isso nem mesmo é permitido).
erikkallen
@erikkallen - esse é um bom ponto. Um retorno fora do bloco TCF seria melhor, mas o código de exemplo seria um pouco forçado :)
annakata 01 de
1
@Castrohenge - não é uma regra rígida e rápida, mas a maioria dos exemplos de copunters nesse tópico são bem planejados, e o único caso válido que vejo é a "cláusula de guarda" (essencialmente o padrão de verificação de dados de entrada no topo de a função e retornando condicionalmente). Esse é um caso perfeitamente válido, mas realmente esses retornos devem ser exceções (novamente, não é difícil e rápido).
annakata,
1
Na verdade, no IE6 e no IE7, finalmente nem sempre é executado em todos os casos devido a um bug do navegador muito sério. Especificamente - se uma exceção for lançada em um bloco try-finally que não está cercado por um try-catch de nível superior, o bloco finally não será executado. Aqui está um caso de teste jsfiddle.net/niallsmart/aFjKq . Esse problema foi corrigido no IE8.
Niall Smart
43

De acordo com ECMA-262 (5ed, dezembro de 2009), nas pp. 96:

A produção TryStatement : try Block Finallyé avaliada da seguinte forma:

  1. Seja B o resultado da avaliação de Bloco.
  2. Seja F o resultado da avaliação Finalmente.
  3. Se F.type for normal, retorne B.
  4. Return F.

E das páginas 36:

O tipo de conclusão é usada para explicar o comportamento de declarações ( break, continue, returne throw) que efectue transferências não-locais de controle. Valores do Tipo de conclusão são triplos da forma (tipo, valor alvo) , onde tipo é um de normal, break, continue, return, ou throw, valor é qualquer valor linguagem ECMAScript ou vazio, e alvo é qualquer identificador ECMAScript ou esvaziar.

É claro que return falseiria definir o tipo de conclusão , finalmente, como retorno , que causam try ... finallya fazer 4. Retorno F .

livibetter
fonte
2
Depois de ler todos os tipos de respostas "basicamente corretas, mas de alguma forma moles e não esclarecedoras" para essa pergunta, esta realmente fez sentido. O ponto chave era que tudo o que "acontecesse" no final do try + catch (return ou throw ou apenas fluxo normal) fosse lembrado enquanto executa a parte finally e então realmente acontecesse apenas se nada acontecer no final de finally.
PreventRage
14

Quando você usa finally, qualquer código dentro desse bloco é disparado antes da saída do método. Como você está usando um return no finallybloco, ele chama return falsee substitui o anterior return trueno trybloco.

(A terminologia pode não estar correta.)

djdd87
fonte
3

porque você está obtendo false é que você retornou em um bloco finally. finalmente o bloco deve ser executado sempre. então suas return truemudanças parareturn false

function example() {
    try {
        return true;
    }
    catch {
        return false;
    }
}
anishMarokey
fonte
3

As reescritas do bloco finalmente tentam o retorno do bloco (falando figurativamente).

Só queria salientar que, se você retornar algo de finalmente, ele será retornado da função. Mas se em finalmente não houver palavra de 'retorno' - será retornado o valor do bloco try;

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

Portanto, -finalmente- returnreescreve o retorno de -try- return.

Mihey Mik
fonte
1

Pelo que eu sei, o finallybloco sempre é executado, independentemente de você ter uma returninstrução dentro tryou não. Portanto, você obtém o valor retornado pela returninstrução dentro do bloco finally.

Eu testei isso com Firefox 3.6.10 e Chrome 6.0.472.63, ambos no Ubuntu. É possível que esse código se comporte de maneira diferente em outros navegadores.

Manoj Govindan
fonte
1

Vou dar uma resposta ligeiramente diferente aqui: Sim, tanto o bloco trye finallysão executados, efinally têm precedência sobre o valor de "retorno" real de uma função. No entanto, esses valores de retorno nem sempre são usados ​​em seu código.

Aqui está o porquê:

  • O exemplo abaixo usará res.send()de Express.js, que cria uma resposta HTTP e a despacha.
  • O seu bloco trye finallyirá executar esta função da seguinte forma:
try {
    // Get DB records etc.
    return res.send('try');
} catch(e) {
    // log errors
} finally {
    return res.send('finally');
}

Este código mostrará a string tryem seu navegador. TAMBÉM, o exemplo mostrará um erro em seu console. A res.send()função é chamada duas vezes . Isso acontecerá com qualquer coisa que seja uma função. O bloco try-catch-finally vai ofuscar esse fato para o olho não treinado, porque (pessoalmente) eu só associoreturn valores com escopos de função.

Imho sua melhor aposta é nunca usar returndentro de um finallybloco . Isso complicará demais o seu código e, potencialmente, mascarará os erros.

Na verdade, há uma configuração de regra de inspeção de código padrão no PHPStorm que fornece um "Aviso" para isso:

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

Então, para que você usa finally?

Eu usaria finallyapenas para limpar coisas. Qualquer coisa que não seja crítica para o valor de retorno de uma função.

Pode fazer sentido se você pensar sobre isso, porque quando você depende de uma linha de código abaixo finally, está assumindo que pode haver erros em tryou catch. Mas esses dois últimos são os blocos de construção reais do tratamento de erros. Basta usar um returnem trye em catchvez disso.

Chama
fonte
0

Retornando de um bloco final

Se o finally-block retornar um valor, esse valor se tornará o valor de retorno de toda a try-catch-finallyinstrução, independentemente de quaisquer returninstruções nos blocos tryecatch

Referência: developer.mozilla.org

Tho
fonte
-2

Finalmente, é suposto que SEMPRE execute no final de um bloco try catch para que (por especificação) seja por isso que você está recebendo o retorno de false. Lembre-se de que é perfeitamente possível que navegadores diferentes tenham implementações diferentes.

Darko Z
fonte
IE8, Firefox 3.6 e Chrome 6: todos iguais;)
bonfo
-3

Que tal isso?

doubleReturn();

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

  try {
    return sex;

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

    alert(sex);
  }
}
Thomas Karlsson
fonte