Pourquoi un retour dans `finally` remplace` try`?

94

Comment fonctionne une instruction return dans un bloc try / catch?

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

Je m'attends à ce que la sortie de cette fonction soit true, mais c'est le cas false!

bonfo
la source
Pour les autres, faites le return false dans le bloc catch, pas enfin.
habibhassani

Réponses:

91

Enfin exécute toujours . C'est à cela qu'il sert, ce qui signifie que son retour est utilisé dans votre cas.

Vous voudrez changer votre code pour qu'il ressemble plus à ceci:

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

En règle générale, vous ne voulez jamais avoir plus d'une instruction return dans une fonction, ce sont des choses comme celles-ci.

Annakata
la source
45
Je dirais qu'avoir plus d'une déclaration de retour n'est pas toujours mauvais - Voir stackoverflow.com/questions/36707/... pour plus de discussion.
Castrohenge
5
Je suis également en désaccord sur la règle du retour unique. Cependant, vous ne devriez jamais revenir de finalement (en C #, ce n'est même pas autorisé).
erikkallen
@erikkallen - c'est un bon point. Un retour en dehors du bloc TCF serait le meilleur mais l'exemple de code serait un peu forcé :)
annakata
1
@Castrohenge - ce n'est pas une règle absolue, mais la plupart des exemples copunter dans ce fil sont assez artificiels, et le seul cas valide que je vois est la "clause de garde" (essentiellement le modèle de vérification des données d'entrée en haut de la fonction et retour conditionnel). C'est un cas parfaitement valable, mais ces retours devraient vraiment être des exceptions (encore une fois pas durs et rapides).
annakata
1
En fait, dans IE6 et IE7, finalement, ne s'exécute pas toujours dans tous les cas en raison d'un bogue de navigateur assez grave. Plus précisément, si une exception est lancée dans un bloc try-finally qui n'est pas entouré par un try-catch de niveau supérieur, le bloc finally ne s'exécutera pas. Voici un cas de test jsfiddle.net/niallsmart/aFjKq . Ce problème a été résolu dans IE8.
Niall Smart
43

Selon ECMA-262 (5ed, décembre 2009), aux pp.96:

La production TryStatement : try Block Finallyest évaluée comme suit:

  1. Soit B le résultat de l'évaluation de Block.
  2. Soit F le résultat de l'évaluation de Final.
  3. Si F.type est normal, renvoyez B.
  4. Retour F.

Et à partir des pages 36:

Le type d' achèvement est utilisé pour expliquer le comportement des déclarations ( break, continue, returnet throw) qui effectuent des transferts non locaux de contrôle. Les valeurs du type d' achèvement sont triplets de la forme (type, valeur cible) , où le type est l' un normal, break, continue, return, ou throw, la valeur est une valeur linguistique ECMAScript ou vide, et la cible est un identificateur ECMAScript ou vide.

Il est clair que return falsefixerait le type d'achèvement de finalement comme retour , ce qui cause try ... finallyà faire 4. Retour F .

livibetter
la source
2
Après avoir lu toutes sortes de réponses «fondamentalement correctes mais quelque peu concises et non clarifiantes» à cette question, celle-ci a en fait fait sens. Le point clé était que tout ce qui "se passe" à la fin du try + catch (retour ou lancer ou juste flux normal) est mémorisé pendant qu'il exécute la partie finally et ne se produit en fait que si rien ne se passe à la fin de finally.
PreventRage
14

Lorsque vous utilisez finally, tout code dans ce bloc se déclenche avant la fin de la méthode. Comme vous utilisez un retour dans le finallybloc, il appelle return falseet remplace le précédent return truedans le trybloc.

(La terminologie n'est peut-être pas tout à fait correcte.)

djdd87
la source
3

pourquoi vous obtenez false est que vous êtes retourné dans un bloc finally. Enfin, le bloc doit toujours s'exécuter. donc vos return truechangements enreturn false

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

Le bloc finally réécrit try block return (au sens figuré).

Je voulais juste souligner que si vous renvoyez quelque chose de finalement, il sera renvoyé par la fonction. Mais si finalement il n'y a pas de mot «return» - il sera retourné la valeur du bloc try;

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

Donc -finalement- returnréécrit le retour de -try- return.

Mihey Mik
la source
1

Autant que je sache, le finallybloc s'exécute toujours , que vous ayez une returninstruction à l'intérieur tryou non. Ergo, vous obtenez la valeur renvoyée par l' returninstruction à l'intérieur du bloc finally.

J'ai testé cela avec Firefox 3.6.10 et Chrome 6.0.472.63 tous deux dans Ubuntu. Il est possible que ce code se comporte différemment dans d'autres navigateurs.

Manoj Govindan
la source
1

Je vais donner une réponse légèrement différente ici: Oui, le bloc tryet finallyest exécuté et finallya la priorité sur la valeur de "retour" réelle d'une fonction. Cependant, ces valeurs de retour ne sont pas toujours utilisées dans votre code.

Voici pourquoi:

  • L'exemple ci-dessous utilisera res.send()Express.js, qui crée une réponse HTTP et la distribue.
  • Votre tryet finallybloc sera à la fois exécuter cette fonction comme ceci:
try {
    // Get DB records etc.
    return res.send('try');
} catch(e) {
    // log errors
} finally {
    return res.send('finally');
}

Ce code affichera la chaîne trydans votre navigateur. AUSSI, l'exemple montrera une erreur dans votre console. La res.send()fonction est appelée deux fois . Cela se produira avec tout ce qui est une fonction. Le bloc try-catch-finally obscurcira ce fait à l'œil non averti, car (personnellement) j'associe uniquement des returnvaleurs aux portées de fonction.

À mon avis, votre meilleur pari est de ne jamais utiliser à l' returnintérieur d'un finallybloc . Cela compliquera trop votre code et masquera potentiellement les erreurs.

En fait, il existe une règle d'inspection de code par défaut configurée dans PHPStorm qui donne un "Avertissement" pour ceci:

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

Alors qu'est-ce que tu utilises finally?

Je n'utiliserais finallyque pour nettoyer des trucs. Tout ce qui n'est pas critique pour la valeur de retour d'une fonction.

Cela peut avoir du sens si vous y réfléchissez, car lorsque vous dépendez d'une ligne de code sous finally, vous supposez qu'il pourrait y avoir des erreurs dans tryou catch. Mais ces deux derniers sont les éléments de base de la gestion des erreurs. Utilisez simplement un returnin tryet à la catchplace.

Flamme
la source
0

De retour d'un bloc final

Si le finally-bloc retourne une valeur, cette valeur devient la valeur de retour de l'ensemble de la try-catch-finallydéclaration, sans tenir compte des returndéclarations du tryet catch-blocks

Référence: developer.mozilla.org

Tho
la source
-2

Enfin est censé s'exécuter TOUJOURS à la fin d'un bloc try catch de sorte que (par spécification) est la raison pour laquelle vous obtenez un faux retourné. Gardez à l'esprit qu'il est tout à fait possible que différents navigateurs aient des implémentations différentes.

Darko Z
la source
IE8, Firefox 3.6 et Chrome 6: tous
pareils
-3

Et ça?

doubleReturn();

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

  try {
    return sex;

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

    alert(sex);
  }
}
Thomas Karlsson
la source