2
votes

Pourquoi les blocs JavaScript try / finally font-ils apparemment revenir la fonction deux fois?

Le bloc finally s'exécute toujours en dernier et l'instruction return retourne le contrôle d'où l'appel de fonction a été effectué. Lorsqu'elle est utilisée ensemble depuis l'intérieur du bloc try / finally, la fonction semble retourner deux fois au lieu d'une fois, lorsqu'elle est utilisée dans un bloc if-else, la valeur de retour du bloc finally prend effet. Le même appel de méthode revient-il deux fois?

Result with wrapped value
true
false
Result when used inside an if statement:
false

le code ci-dessus produit la sortie suivante:

function print(value) {
    console.log(value);
    return value;
}

function testWrapped() {
    try {
        return print(true);
    } finally {
        return print(false);
    }
}

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


console.log("Result with wrapped value");
testWrapped();


console.log("Result when used inside an if statement:");
if (test()) {
    console.log("true");
} else {
    console.log("false");
}


1 commentaires

Ceci est mon explication pour ce comportement, la fonction évalue l'expression pour la valeur de retour mais avant de retourner, elle exécute le bloc finally, qui est le comportement attendu, car il n'y a rien pour remplacer les effets du bloc finally, la dernière instruction renvoie le contrôle au corps appelant. Suis-je sur la bonne voie? Quelles sont vos pensées?


3 Réponses :



3
votes

Les deux sont évalués , mais seul le second est en fait renvoyé .

Puisque l'évaluation de print () a le côté -effet de la sortie vers la console, vous pouvez voir l'évaluation. Mais si vous deviez console.log (testWrapped ()) , vous verriez la valeur retournée après les deux valeurs évaluées.

Votre code équivaut à:

< pre> XXX

J'espère que cela clarifiera ce qui se passe.


1 commentaires

Je pensais aussi dans ce sens, la fonction 'print' donne l'impression qu'elle a été renvoyée deux fois, mais en réalité, seule l'expression de retour a été évaluée et la valeur réelle renvoyée est la deuxième du bloc finally (plus de contexte dans le commentaire sous la question). Merci d'avoir clarifié cela.



2
votes

Pour en savoir plus, la spec dit:

TryStatement : essayez Bloquer enfin

  1. Soit B le résultat de l’évaluation de Block .
  2. Soit F le résultat de l'évaluation Enfin .
  3. Si F . [[type]] est normal, soit F B .
  4. Si F . [[type]] est return, ou F . [[type]] est throw, renvoie Completion ( F ).
  5. Si F . [[value]] n'est pas vide, renvoyez Completion ( F ).
  6. Achèvement du retour {[[type]]: F . [[type]], [[value]]: undefined , [[target]]: F. [[cible]]}.

En appliquant ceci à votre code testWrapped () ,

  1. Le bloc try est évalué. Les effets secondaires de print (true) se produisent, donc true apparaîtra dans la console. Le bloc try retourne, donc le résultat de son évaluation est un Achèvement avec le type return et la valeur quelle que soit l'impression (true): true . Ce message n'est pas encore renvoyé.
  2. Le bloc finally est évalué. Même chose: false dans la console, Achèvement {[[type]]: return , [[value]]: false }.
  3. "Si F. [[type]] est normal" Ce n'est pas le cas. Suivant.
  4. C'est là que le retour se produit réellement, et c'est le retour du bloc finally : false. Résultat final: true false dans la console et testWrapped () renvoie false.

Et l'instruction if :

    Le bloc try de
  1. test est évalué: Achèvement {[[type]]: return , [[value]]: vrai }.
  2. Le bloc finally de
  3. test est évalué: Achèvement {[[type]]: return , [[value]]: faux }.
  4. Nada.
  5. L'achèvement de
  6. enfin est renvoyé: faux. test () donne la valeur false et le bloc else s'exécute.

0 commentaires