¿Por qué un retorno en "finalmente" anula "intentar"?

94

¿Cómo funciona una declaración de devolución dentro de un bloque try / catch?

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

Espero que la salida de esta función sea true, ¡pero en cambio lo es false!

bonfo
fuente
Para otros, haga el retorno falso en el bloque de captura, no finalmente.
Habibhassani

Respuestas:

91

Finalmente siempre se ejecuta. Para eso es, lo que significa que su retorno se usa en su caso.

Querrá cambiar su código para que sea más así:

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

En términos generales, nunca querrá tener más de una declaración de retorno en una función, este es el motivo.

Annakata
fuente
45
Yo diría que tener más de una declaración de devolución no siempre es malo. Consulte stackoverflow.com/questions/36707/… para obtener más información.
Castrohenge
5
Yo también estoy en desacuerdo con la regla de devolución única. Sin embargo, nunca debe regresar de finalmente (en C #, ni siquiera está permitido).
erikkallen
@erikkallen, ese es un buen punto. Un retorno fuera del bloque TCF sería lo mejor, pero el código de ejemplo sería un poco forzado :)
annakata
1
@Castrohenge: no es una regla estricta y rápida, pero la mayoría de los ejemplos de copunter en ese hilo son bastante artificiales, y el único caso válido que veo es la "cláusula de protección" (esencialmente el patrón de verificación de datos de entrada en la parte superior de la función y regresando condicionalmente). Ese es un caso perfectamente válido, pero en realidad esas devoluciones deberían ser excepciones (de nuevo, no estrictas y rápidas).
annakata
1
En realidad, en IE6 e IE7, finalmente no siempre se ejecuta en todos los casos debido a un error bastante grave del navegador. Específicamente, si se lanza una excepción en un bloque de intentar finalmente que no esté rodeado por un intento de captura de nivel superior, entonces el bloque finalmente no se ejecutará. Aquí hay un caso de prueba jsfiddle.net/niallsmart/aFjKq . Este problema se solucionó en IE8.
Niall Smart
43

Según ECMA-262 (5ed, diciembre de 2009), en págs. 96:

La producción TryStatement : try Block Finallyse evalúa de la siguiente manera:

  1. Sea B el resultado de evaluar a Block.
  2. Sea F el resultado de evaluar finalmente.
  3. Si F.type es normal, devuelva B.
  4. Regresar F.

Y de las págs. 36:

El tipo de finalización se utiliza para explicar el comportamiento de los estados ( break, continue, returny throw) que realizan las transferencias no locales de control. Valores del tipo de finalización son triples de la forma (tipo, valor, objetivo) , donde tipo es uno de normal, break, continue, return, o throw, valor es cualquier valor lenguaje ECMAScript o vacío, y diana es cualquier identificador ECMAScript o vacío.

Está claro que return falsesería establecer el tipo de terminación de fin como de retorno , lo que causa try ... finallyque hacer 4. Volver F .

Livibetter
fuente
2
Después de leer todo tipo de respuestas "básicamente correctas, pero de alguna manera blandas y no aclaratorias" a esta pregunta, esta realmente hizo que tuviera sentido. La parte clave fue que todo lo que "sucede" al final del intento + captura (retorno o lanzamiento o simplemente flujo normal) se recuerda mientras se ejecuta la parte final y luego ocurre realmente solo si no sucede nada al final del final.
Prevenir la ira
14

Cuando lo usa finally, cualquier código dentro de ese bloque se activa antes de que salga el método. Debido a que está utilizando un retorno en el finallybloque, llama return falsey anula el anterior return trueen el trybloque.

(Es posible que la terminología no sea del todo correcta).

djdd87
fuente
3

la razón por la que se está volviendo falso es que regresó en un bloque finalmente. finalmente el bloque debería ejecutarse siempre. entonces tu return truecambia areturn false

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

El bloque finalmente reescribe el retorno del bloque de prueba (en sentido figurado).

Solo quería señalar que si devuelve algo de finalmente, se devolverá desde la función. Pero si finalmente no hay una palabra de 'retorno', se devolverá el valor del bloque try;

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

Entonces -finalmente- returnreescribe el retorno de -intentar- return.

Mihey Mik
fuente
1

Hasta donde yo sé, el finallybloque siempre se ejecuta, independientemente de si tiene una returndeclaración dentro tryo no. Ergo, obtienes el valor devuelto por elreturn declaración dentro del bloque finalmente.

Probé esto con Firefox 3.6.10 y Chrome 6.0.472.63 ambos en Ubuntu. Es posible que este código se comporte de manera diferente en otros navegadores.

Manoj Govindan
fuente
1

Voy a dar una respuesta ligeramente diferente aquí: Sí, tanto el bloque tryy finallyse ejecutan, y finallytiene prioridad sobre el valor de "retorno" real para una función. Sin embargo, estos valores de retorno no siempre se usan en su código.

Este es el por qué:

  • El siguiente ejemplo utilizará res.send()de Express.js, que crea una respuesta HTTP y la envía.
  • Tu tryy el finallybloque ejecutarán esta función así:
try {
    // Get DB records etc.
    return res.send('try');
} catch(e) {
    // log errors
} finally {
    return res.send('finally');
}

Este código mostrará la cadena tryen su navegador. TAMBIÉN, el ejemplo mostrará un error en su consola. La res.send()función se llama dos veces . Esto sucederá con todo lo que sea una función. El bloque try-catch-finalmente ocultará este hecho al ojo inexperto, porque (personalmente) solo asocio returnvalores con ámbitos de función.

En mi humilde opinión, su mejor opción es no usar nunca returndentro de un finallybloque . Complicará demasiado su código y potencialmente enmascarará errores.

De hecho, hay una regla de inspección de código predeterminada configurada en PHPStorm que da una "Advertencia" para esto:

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

Entonces, ¿para qué usas finally?

Solo lo usaría finallypara limpiar cosas. Todo lo que no sea crítico para el valor de retorno de una función.

Puede tener sentido si lo piensa, porque cuando depende de una línea de código debajo finally, está asumiendo que podría haber errores en tryo catch. Pero esos dos últimos son los bloques de construcción reales del manejo de errores. Solo usa returnin tryy en su catchlugar.

Fuego
fuente
0

Volviendo de un bloque finalmente

Si el finally-block devuelve un valor, este valor se convierte en el valor de retorno de la try-catch-finallydeclaración completa , independientemente de las returndeclaraciones en los bloques tryy catch.

Referencia: developer.mozilla.org

aunque
fuente
-2

Finalmente, se supone que SIEMPRE se ejecuta al final de un bloque try catch, de modo que (por especificación) es la razón por la que obtiene una devolución falsa. Tenga en cuenta que es muy posible que diferentes navegadores tengan diferentes implementaciones.

Darko Z
fuente
IE8, Firefox 3.6 y Chrome 6: todos iguales;)
bonfo
-3

¿Qué pasa con esto?

doubleReturn();

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

  try {
    return sex;

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

    alert(sex);
  }
}
Thomas Karlsson
fuente