Warum überschreibt eine Rückkehr in "endlich" "versuchen"?

91

Wie funktioniert eine return-Anweisung in einem try / catch-Block?

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

Ich erwarte die Ausgabe dieser Funktion true, aber stattdessen ist es false!

Bonfo
quelle
Für andere machen Sie die Rückgabe false im catch-Block, nicht endgültig.
Habibhassani

Antworten:

89

Endlich immer ausgeführt. Dafür ist es da, was bedeutet, dass die Rückgabe in Ihrem Fall verwendet wird.

Sie möchten Ihren Code so ändern, dass er eher so aussieht:

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

Im Allgemeinen möchten Sie nie mehr als eine return-Anweisung in einer Funktion haben. Solche Dinge sind der Grund dafür.

Annakata
quelle
45
Ich würde argumentieren, dass es nicht immer schlecht ist, mehr als eine return-Anweisung zu haben. Weitere Informationen finden Sie unter stackoverflow.com/questions/36707/… .
Castrohenge
5
Auch ich bin nicht einverstanden mit der One-Return-Regel. Sie sollten jedoch niemals endgültig zurückkehren (in C # ist dies nicht einmal erlaubt).
Erikkallen
@erikkallen - das ist ein guter Punkt. Eine Rückkehr außerhalb des TCF-Blocks wäre am besten, aber der Beispielcode wäre etwas erzwungen :)
annakata
1
@Castrohenge - es ist keine feste Regel, aber die meisten Copunter-Beispiele in diesem Thread sind ziemlich erfunden, und der einzig gültige Fall, den ich sehe, ist die "Guard-Klausel" (im Wesentlichen das Muster der Überprüfung von Eingabedaten oben in die Funktion und Rückgabe bedingt). Das ist ein absolut gültiger Fall, aber eigentlich sollten diese Rückgaben Ausnahmen sein (wieder nicht hart und schnell).
Annakata
1
Tatsächlich wird es in IE6 und IE7 aufgrund eines ziemlich schwerwiegenden Browserfehlers nicht immer in allen Fällen ausgeführt. Insbesondere: Wenn eine Ausnahme in einem Try-finally-Block ausgelöst wird, der nicht von einem Try-Catch höherer Ebene umgeben ist, wird der finally-Block nicht ausgeführt. Hier ist ein Testfall jsfiddle.net/niallsmart/aFjKq . Dieses Problem wurde in IE8 behoben.
Niall Smart
43

Gemäß ECMA-262 (5ed, Dezember 2009), S. 96:

Die Produktion TryStatement : try Block Finallywird wie folgt bewertet:

  1. Sei B das Ergebnis der Auswertung von Block.
  2. Sei F das Ergebnis der Bewertung von Schließlich.
  3. Wenn F.type normal ist, geben Sie B zurück.
  4. Rückgabe F.

Und ab S. 36:

Die Fertigstellung Typ wird verwendet , um das Verhalten von Aussagen zu erklären ( break, continue, returnund throw) , die nicht - lokale Transfers von Steuer auszuführen. Werte des Completion - Typs sind Tripel von der Form (Typ, Wert, Ziel) , in dem Typ eines ist normal, break, continue, return, oder throw, Wert ist jeder ECMAScript Sprache Wert oder leer ist , und Ziel ist irgendein ECMAScript Identifikator oder leer ist .

Es ist klar , dass return falseVollendung Art gesetzt würde schließlich als Rückkehr , die dazu führen , try ... finallyzu tun 4. Rückkehr F .

livibetter
quelle
2
Nachdem ich alle möglichen "grundsätzlich korrekten, aber irgendwie matschigen und nicht klärenden" Antworten auf diese Frage gelesen hatte, machte diese Frage tatsächlich Sinn. Das Schlüsselbit war, dass alles, was am Ende von try + catch (return oder throw oder nur normaler Fluss) "passiert" , während der Ausführung des finally-Teils gespeichert wird und dann tatsächlich nur dann passiert, wenn am Ende von finally nichts passiert.
PreventRage
14

Wenn Sie verwenden finally, wird jeder Code in diesem Block ausgelöst, bevor die Methode beendet wird. Da Sie im finallyBlock eine Rückgabe verwenden , wird return falsedie vorherige return trueim tryBlock aufgerufen und überschrieben .

(Die Terminologie ist möglicherweise nicht ganz richtig.)

djdd87
quelle
3

Warum Sie falsch werden, ist, dass Sie in einem finally-Block zurückgegeben werden. Schließlich sollte Block immer ausgeführt werden. also deine return trueänderungen anreturn false

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

Die endgültigen Blockumschreibungen versuchen die Blockrückgabe (im übertragenen Sinne).

Ich wollte nur darauf hinweisen, dass, wenn Sie etwas von endlich zurückgeben, es von der Funktion zurückgegeben wird. Wenn es jedoch endlich kein 'return'-Wort gibt, wird der Wert vom try-Block zurückgegeben.

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

Also returnschreibt -end- die Rückkehr von -try- neu return.

Mihey Mik
quelle
1

Soweit ich weiß, wird der finallyBlock immer ausgeführt, unabhängig davon, ob Sie eine returnAnweisung enthalten tryoder nicht. Ergo erhalten Sie den vom zurückgegebenen Wertreturn Anweisung im finally-Block zurückgegeben wird.

Ich habe dies mit Firefox 3.6.10 und Chrome 6.0.472.63 in Ubuntu getestet. Es ist möglich, dass sich dieser Code in anderen Browsern anders verhält.

Manoj Govindan
quelle
0

Rückkehr von einem Endblock

Wenn der finally-block einen Wert zurückgibt, wird dieser Wert zum Rückgabewert der gesamten try-catch-finallyAnweisung, unabhängig von den returnAnweisungen in den Blöcken tryund catch-blocks

Referenz: developer.mozilla.org

Tho
quelle
0

Ich werde hier eine etwas andere Antwort geben: Ja, sowohl der tryals auch der finallyBlock werden ausgeführt und haben finallyVorrang vor dem tatsächlichen "Rückgabewert" für eine Funktion. Diese Rückgabewerte werden jedoch nicht immer in Ihrem Code verwendet.

Hier ist der Grund:

  • Das folgende Beispiel wird verwendet res.send() Express.js verwendet, das eine HTTP-Antwort erstellt und diese versendet.
  • Ihr tryund Ihr finallyBlock führen diese Funktion folgendermaßen aus:
try {
    // Get DB records etc.
    return res.send('try');
} catch(e) {
    // log errors
} finally {
    return res.send('finally');
}

Dieser Code zeigt die Zeichenfolge tryin Ihrem Browser an. AUCH das Beispiel zeigt einen Fehler in Ihrer Konsole. Die res.send()Funktion wird zweimal aufgerufen . Dies geschieht mit allem, was eine Funktion ist. Der Try-Catch-finally-Block wird diese Tatsache für das ungeübte Auge verschleiern, weil ich (persönlich) nur assoziierereturn Werte nur mit Funktionsbereichen .

Imho ist Ihre beste Wette, nie returninnerhalb eines finallyBlocks zu verwenden . Dies wird Ihren Code überkomplizieren und möglicherweise Fehler maskieren.

Tatsächlich gibt es in PHPStorm eine Standard-Code-Inspektionsregel, die eine "Warnung" dafür gibt:

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

Also, wofür benutzt du finally?

ich würde ... benutzen finally nur Sachen aufräumen. Alles, was für den Rückgabewert einer Funktion nicht kritisch ist.

Es kann sinnvoll sein, wenn Sie darüber nachdenken, denn wenn Sie von einer Codezeile unter abhängen finally, gehen Sie davon aus, dass es Fehler in tryoder geben könnte catch. Die letzten beiden sind jedoch die eigentlichen Bausteine ​​für die Fehlerbehandlung. Verwenden Sie stattdessen einfach ein returnIn tryund catch.

Flamme
quelle
-2

Schließlich soll IMMER am Ende eines try catch-Blocks ausgeführt werden, damit (nach Angabe) falsch zurückgegeben wird. Beachten Sie, dass es durchaus möglich ist, dass verschiedene Browser unterschiedliche Implementierungen haben.

Darko Z.
quelle
IE8, Firefox 3.6 und Chrome 6: alle gleich;)
bonfo
-3

Was ist damit?

doubleReturn();

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

  try {
    return sex;

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

    alert(sex);
  }
}
Thomas Karlsson
quelle