Perché un ritorno in `finalmente` ha la precedenza su` try`?


94

Come funziona un'istruzione return all'interno di un blocco try / catch?

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

Mi aspetto che l'output di questa funzione sia true, ma invece lo è false!


Per altri, restituisci false nel blocco catch, non finalmente.
habibhassani

Risposte:


91

Infine viene sempre eseguito. Ecco a cosa serve, il che significa che il suo ritorno viene utilizzato nel tuo caso.

Ti consigliamo di modificare il codice in modo che sia più simile a questo:

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

In generale, non vuoi mai avere più di un'istruzione return in una funzione, cose come queste sono il motivo.


45
Direi che avere più di una dichiarazione di ritorno non è sempre male - Vedi stackoverflow.com/questions/36707/… per ulteriori discussioni.
Castrohenge

5
Anch'io non sono d'accordo sulla regola del rimpatrio. Non dovresti mai tornare da finalmente, però (in C #, non è nemmeno consentito).
erikkallen

@erikkallen - questo è un buon punto. Un ritorno al di fuori del blocco TCF sarebbe il migliore, ma il codice di esempio sarebbe un po 'forzato :)
annakata

1
@Castrohenge - non è una regola rigida e veloce, ma la maggior parte degli esempi di copunter in quel thread sono piuttosto artificiosi, e l'unico caso valido che vedo è la "clausola di guardia" (essenzialmente il modello di controllo dei dati di input nella parte superiore la funzione e restituendo in modo condizionale). Questo è un caso perfettamente valido, ma in realtà quei ritorni dovrebbero essere eccezioni (di nuovo non difficili e veloci).
annakata

1
In realtà in IE6 e IE7, alla fine non sempre viene eseguito in tutti i casi a causa di un bug del browser piuttosto serio. In particolare, se viene generata un'eccezione in un blocco try-latest che non è circondato da un try-catch di livello superiore, il blocco finalmente non verrà eseguito. Ecco un caso di prova jsfiddle.net/niallsmart/aFjKq . Questo problema è stato risolto in IE8.
Niall Smart

43

Secondo ECMA-262 (5ed, dicembre 2009), a pp.96:

La produzione TryStatement : try Block Finallyviene valutata come segue:

  1. Sia B il risultato della valutazione di Blocco.
  2. Sia F il risultato della valutazione Finalmente.
  3. Se il tipo F. è normale, restituisci B.
  4. Ritorno F.

E da pp.36:

Il tipo di completamento è utilizzato per spiegare il comportamento di istruzioni ( break, continue, returne throw) che eseguono trasferimenti non locali di controllo. Valori del tipo di completamento sono triple della forma (tipo, valore, target) , dove tipo è uno di normal, break, continue, return, o throw, il valore è un valore linguaggio ECMAScript o vuoto, ed obiettivo è qualsiasi identificatore ECMAScript o svuotare.

E 'chiaro che return falsesarebbe impostare il tipo di completamento , infine , come il ritorno , che causano try ... finallya fare 4. Return F .


2
Dopo aver letto tutti i tipi di risposte "fondamentalmente corrette ma in qualche modo morbide e non chiarenti" a questa domanda, questa in realtà aveva senso. Il punto chiave era che qualunque cosa "accada" alla fine di try + catch (return o throw o semplicemente flusso normale) viene ricordata mentre esegue la parte finalmente e poi accade effettivamente solo se non succede nulla alla fine di finalmente.
PreventRage

14

Quando si utilizza finally, qualsiasi codice all'interno di quel blocco viene attivato prima che il metodo termini. Poiché stai usando un ritorno nel finallyblocco, chiama return falsee sovrascrive il precedente return truenel tryblocco.

(La terminologia potrebbe non essere corretta.)


3

il motivo per cui stai diventando falso è che sei tornato in un blocco finale. infine il blocco dovrebbe essere eseguito sempre. quindi le tue return truemodifiche areturn false

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

3

La riscrittura del blocco finale prova il ritorno del blocco (in senso figurato).

Volevo solo sottolineare che se restituisci qualcosa da finalmente, allora verrà restituito dalla funzione. Ma se alla fine non c'è una parola 'return' - verrà restituito il valore dal blocco try;

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

Quindi -finalmente- returnriscrive il ritorno di -try- return.


1

Per quanto ne so, il finallyblocco viene sempre eseguito, indipendentemente dal fatto che tu abbia returnun'istruzione all'interno tryo meno. Ergo, ottieni il valore restituito returndall'istruzione all'interno del blocco finale.

L'ho provato con Firefox 3.6.10 e Chrome 6.0.472.63 entrambi su Ubuntu. È possibile che questo codice si comporti in modo diverso in altri browser.


1

Sto andando dare una risposta un po 'diverso qui: Si, sia l' trye finallyblocco vengono eseguiti, e finallyha la precedenza sul valore effettivo "ritorno" per una funzione. Tuttavia, questi valori restituiti non vengono sempre utilizzati nel codice.

Ecco perché:

  • L'esempio seguente userà res.send()da Express.js, che crea una risposta HTTP e la invia.
  • Il tuo trye finallyblocco eseguirà sia questa funzione in questo modo:
try {
    // Get DB records etc.
    return res.send('try');
} catch(e) {
    // log errors
} finally {
    return res.send('finally');
}

Questo codice mostrerà la stringa trynel tuo browser. INOLTRE, l'esempio mostrerà un errore nella tua console. La res.send()funzione viene chiamata due volte . Questo accadrà con tutto ciò che è una funzione. Il blocco try-catch-latest offuscherà questo fatto a un occhio inesperto, perché (personalmente) associo i returnvalori solo agli ambiti delle funzioni.

Imho la tua scommessa migliore è non usare mai returnall'interno di un finallyblocco . Complicherà eccessivamente il codice e potenzialmente maschererà gli errori.

In effetti, in PHPStorm esiste una regola di ispezione del codice predefinita che fornisce un "Avviso" per questo:

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

Allora per cosa usi finally?

Userei finallysolo per ripulire le cose. Tutto ciò che non è critico per il valore restituito di una funzione.

Può avere senso se ci pensi, perché quando dipendi da una riga di codice sotto finally, stai assumendo che potrebbero esserci errori in tryo catch. Ma questi ultimi 2 sono gli elementi costitutivi reali della gestione degli errori. Basta usare un returnin trye catchinvece.


0

Di ritorno da un blocco definitivo

Se finally-block restituisce un valore, questo valore diventa il valore restituito dell'intera try-catch-finallyistruzione, indipendentemente da qualsiasi returnistruzione in trye catch-block

Riferimento: developer.mozilla.org


-2

Infine si suppone che venga SEMPRE eseguito alla fine di un blocco try catch in modo che (secondo le specifiche) sia per questo che viene restituito false. Tieni presente che è del tutto possibile che browser diversi abbiano implementazioni diverse.


IE8, Firefox 3.6 e Chrome 6: tutti uguali;)
bonfo

-3

Che dire di questo?

doubleReturn();

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

  try {
    return sex;

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

    alert(sex);
  }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.