try-catch in javascript ... non è una buona pratica?


69

Esiste una disposizione per il blocco try-catch in javascript . Mentre in java o in qualsiasi altra lingua è obbligatorio avere la gestione degli errori, non vedo nessuno che li utilizza in javascript per una maggiore estensione. Non è una buona pratica o semplicemente non ne abbiamo bisogno in JavaScript?


2
While in java or *any other language* it is mandatory to have error handling...- Non proprio. Java, sì, ma ci sono molti linguaggi che non insistono su try-catch (come C #).
Jim G.

È perché non è possibile utilizzarli in un ambiente asincrono. Li uso spesso per sincronizzare il codice con un livello di astrazione inferiore, ad esempio trasformando qualcosa in qualcosa, ecc ...
inf3rno,

Scommetto che vedrai più try-catch nel codice lato server che nel codice lato client. La maggior parte del codice lato client a cui sei a conoscenza non sta facendo nulla di importante. Scommetto che ridurre al minimo i KB è più importante del ripristino da ogni errore, nella maggior parte delle applicazioni e delle circostanze sul lato browser.
svidgen,

C'è un altro modo per evitare di provare a catturare usando forse ed entrambi (monadi) avevamo un web scrapper scritto nel nodo. Siamo stati in grado di rimuovere tutti i tentativi di cattura utilizzandolo.
user93

Risposte:


66

Uno dovrebbe evitare throwerrori come il modo per superare le condizioni di errore nelle applicazioni.

L' throwistruzione deve essere utilizzata solo "Per questo non dovrebbe mai accadere, crash e masterizzazione. Non recuperare in modo elegante in alcun modo"

try catch tuttavia viene utilizzato in situazioni in cui oggetti host o ECMAScript potrebbero generare errori.

Esempio:

var json
try {
    json = JSON.parse(input)
} catch (e) {
    // invalid json input, set to null
    json = null
}

I consigli nella community node.js sono di passare errori nei callback (poiché gli errori si verificano solo per operazioni asincrone) come primo argomento

fs.readFile(uri, function (err, fileData) {
    if (err) {
        // handle
        // A. give the error to someone else
        return callback(err)
        // B. recover logic
        return recoverElegantly(err)
        // C. Crash and burn
        throw err
    }
    // success case, handle nicely
})

Ci sono anche altri problemi come try / catch è davvero costoso ed è brutto e semplicemente non funziona con operazioni asincrone.

Pertanto, poiché le operazioni sincrone non devono generare un errore e non funzionano con operazioni asincrone, nessuno usa try catch tranne gli errori generati da oggetti host o ECMAScript


2
Non direi che nessuno usa provare a catturare, nella maggior parte dei casi è solo lo strumento sbagliato per il lavoro. Quando ci sono circostanze davvero eccezionali, può essere utile lanciarne una Error, ma sono poche e lontane tra loro.
zzzzBov,

7
@zzzzBov Non c'è niente di sbagliato nel lanciare errori per il caso C, crash e burn. Non penso che dovresti rilevare errori e ripristinarli. Ad esempio, document.getElementByIdnon viene generato quando l'elemento non esiste, ma semplicemente ritorna null. Lo stesso si può fare per quasi tutti i casi
Raynos,

4
@Raynos, il lancio da una funzione di sincronizzazione è totalmente accettabile e ha senso in quel caso d'uso. Restituire l'errore alla richiamata è asincronizzarsi poiché l'errore di lancio è sincronizzare.
sbartell,

@Raynos ha qualche buon consiglio per evitare di usare Errori / Eccezioni per il controllo del flusso sul lato client (ambiente non Nodo)? Ho trovato questo post su StackOverflow , ma è principalmente orientato verso Java
blong

@ b.long simple. non gettare mai errori. Problema risolto.
Raynos,

32

Try / catch in Javascript non è a prova di proiettile come in altre lingue, a causa della natura asincrona di Javascript. Considera questo frammento:

try {
    setTimeout(function() {
        do_something_that_throws();
    }, 1000);
}
catch (e) {
    alert("You won't see this!");
}

Il problema è che il flusso di controllo lascia il tryblocco prima che do_something_that_throws()venga eseguito, quindi l'errore generato nel callback non viene mai rilevato.

Quindi provare / catturare è fondamentalmente inappropriato in molti casi, e non è sempre ovvio se qualcosa esegue il codice in modo asincrono o meno. Fortunatamente, javascript con il suo peculiare idioma di callback asincrono a thread singolo e il suo supporto per chiusure effettive offre un'alternativa elegante: la gestione degli errori di stile a passaggio continuo. Basta passare la risposta corretta a qualsiasi errore come funzione, ad esempio:

setTimeout(function () {
    do_something_that_calls_err(function(err) {
        alert("Something went wrong, namely this: " + err);
    }),
    1000);

5
non è nemmeno a prova di proiettile in altre lingue. Porta quel codice in qualsiasi lingua che supporti i callback asincroni e fallirà anche.
Raynos,

2
@Raynos: hai ragione; tuttavia, altre lingue (o meglio, le loro culture di supporto) non acquistano questo pesantemente nel linguaggio del callback asincrono come fa Javascript, e a causa della natura multi-thread della maggior parte degli altri ambienti, le carenze di try / catch sono più evidenti e circondato da molte altre avvertenze, quindi le persone camminano con cautela in situazioni di richiamata multi-thread / asincrone e sono più consapevoli delle potenziali insidie.
martedì

È davvero dovuto alla "natura asincrona" di JavaScript? Per quanto posso vedere, Try / Catch potrebbe teoricamente essere fatto funzionare in modo lessicale come il modo in cui gli identificatori vengono chiusi lessicamente; semplicemente non funziona così in JavaScript.
Brian Gordon,

2
In node.js> = 0.8 vale la pena notare che è possibile provare / catturare in modo asincrono, vedere la mia domanda stackoverflow.com/questions/14301839/…
Benjamin Gruenbaum,

L'unica alternativa al try-catch sincrono è lo stile di passaggio di continuazione asincrono?
CMCDragonkai,

23

Molte di queste risposte sono un po 'vecchie e non tengono conto delle nuove funzionalità ES7 asynce await.

Usando async/ awaitora puoi ottenere un flusso di controllo asincrono come desideri:

async function email(address) {
  try {
    // Do something asynchronous that may throw...
    await sendEmail({ to: address, from: 'noreply@domain.com`, subject: 'Hello' })
  } catch(err) {
    if (err instanceof SomeCustomError) {
      elegantlyHandleError(err)
    } else {
      throw err
    } 
  }
})

Ulteriori informazioni su async/ awaitqui . Puoi usare async/ awaitora usando babel .


Ma è simile a un codice sincrono
Atul Agrawal,

@AtulAgrawal sì, questo è il punto. Async / await ti permette di scrivere codice asincrono in uno stile sincrono in modo da evitare "callback hell" e concatenare molte promesse insieme. Secondo me è un modo molto divertente di scrivere un codice asincrono
Dana Woodman,

quindi qual è il vantaggio dell'utilizzo di JavaScript se stiamo rendendo il codice asincrono sincrono. perché la maggior parte delle persone usa javascript a causa della sua natura asincrona
Atul Agrawal,

2
@AtulAgrawal ottieni il meglio da entrambi i mondi - ti piace la natura asincrona della lingua (poiché il codice sopra verrà comunque eseguito asincrono - liberando il thread e tutto il resto) e ottieni i vantaggi di uno stile di programmazione più intuitivo per i programmatori. Non è senza problemi, però ...
ZenMaster

15

try-catch in javascript è valido e utile come in qualsiasi altra lingua che li implementa. C'è una delle ragioni principali per cui non viene utilizzato tanto in JavaScript come in altre lingue. È lo stesso motivo per cui javascript è visto come un brutto linguaggio di scripting, è lo stesso motivo per cui le persone pensano che i programmatori javascript non siano veri programmatori:

  • Javascript è un linguaggio incredibilmente accessibile e pervasivo

Il semplice fatto che così tante persone siano esposte a javascript (in virtù dell'unica lingua supportata dai browser) significa che hai un sacco di codice non professionale là fuori. Naturalmente ci sono anche molte ragioni minori:

  • alcune cose in javascript sono asincrone e quindi non sono in catchgrado (cose asincrone)
  • si è parlato in modo esagerato di come il catch-catch abbia avuto un enorme successo in termini di prestazioni. Ha un po 'di prestazioni , ma per la maggior parte del codice ne vale la pena.
  • javascript è stato (purtroppo) implementato in un modo che spesso ignora silenziosamente gli errori (cambiando automaticamente le stringhe in numeri per esempio)

Indipendentemente da ciò, dovrebbe essere usato try-catch , ma ovviamente dovresti imparare come usarli correttamente - come tutto il resto nella programmazione.


3
E perché mai hai downvote, oh silenzioso downvoter?
user250878,

Concordato. Penso che la risposta accettata sia generalmente vera, ma ci sono buoni motivi per usare try-catch, e persino lanciare, oltre a quando si tratta di oggetti nativi. Quando viene generato un errore anziché essere passato a un callback, interrompe ulteriormente l'esecuzione e salta lo stack sul primo blocco che può gestirlo. Questo è un grande vantaggio e ha perfettamente senso per le operazioni sincrone, specialmente se comportano un annidamento profondo. Sembra assurdo suggerire che le eccezioni siano "cattive" (beh, se non per ovvie ragioni) - in realtà sono uno strumento molto utile con un "potere" unico.
Punto

2
Ti sei mai preso il tempo di leggere il codice sorgente di, diciamo, jQuery? Quasi nessun tentativo di cattura lì dentro, tranne per esattamente quegli scenari menzionati nella risposta accettata: per rilevare caratteristiche e utilizzare oggetti nativi / host che generano errori. Chiamare codice che non usa molto try-catch (come jQuery) "non professionale" sembra sciocco. Ad essere sincero, penso che siano soprattutto i nuovi programmatori Javascript che provengono da Java che tendono a utilizzare eccessivamente le funzionalità del linguaggio come try-catch.
Stijn de Witt,

6

Credo che gran parte del motivo che try..catchè raro in JavaScript sia dovuto al fatto che la lingua ha una tolleranza piuttosto elevata per l'errore. La maggior parte delle situazioni può essere gestita utilizzando controlli del codice, valori predefiniti corretti ed eventi asincroni. In alcuni casi, semplicemente usando un modello si eviteranno problemi:

function Foo() {
    //this may or may not be called as a constructor!!
    //could accidentally overwrite properties on window
}

function Bar() {
    if (!(this instanceof Bar)) {
        return new Bar();
    }
    //this will only work on Bar objects, and wont impact window
}

Alcuni dei principali problemi in altre lingue che causano eccezioni semplicemente non esistono in JS. Il casting di tipo non è necessario nella maggior parte delle volte. Invece, il metodo preferito è in genere quello di controllare le caratteristiche (applicando una particolare interfaccia):

function doFoo(arg) {
    if (arg.foo) {
        arg.foo();
    } else {
        Bar.prototype.foo.call(arg);
    }
}

Con l'aggiunta di async/ awaitalla lingua, try..catchsta diventando sempre più diffusa. Le promesse sono la forma asincrona di try..catch, ha senso che ci si dovrebbe aspettare:

doSomething().then(
  doSomethingWithResult,
  doSomethingWithError
)

essere invece scritto come:

try {
  const result = await doSomething()
  doSomethingWithResult(result)
} catch (e) {
  doSomethingWithError(e)
}

3

Forse un altro motivo per cui try / catch non è molto usato in Javascript è che il costrutto non era disponibile nelle primissime versioni di Javascript ... è stato aggiunto in seguito.

Di conseguenza, alcuni browser meno recenti non lo supportano. (In effetti, potrebbe causare un errore parser / sintassi in alcuni browser meno recenti, qualcosa che è più difficile "programmare in modo difensivo" rispetto alla maggior parte degli altri tipi di errori.)

Ancora più importante, dal momento che inizialmente non era disponibile, le funzioni integrate di Javascript inizialmente rilasciate (ciò che si chiamerebbe funzioni di "libreria" in molte lingue) non ne fanno uso. (Non funziona molto bene per "rilevare" un errore da someobject.somefunction () se non "getta" ma invece restituisce "null" quando incontra un problema.)


Ancora un'altra possibile ragione è che il meccanismo try / catch non sembra inizialmente necessario (e non sembra ancora così utile). È veramente necessario solo quando le chiamate vengono annidate di routine a diversi livelli di profondità; solo restituire una sorta di ERRNO funzionerebbe bene per le chiamate dirette (anche se per renderlo davvero utile ogni volta che è disponibile, la migliore pratica nella maggior parte delle lingue è usarla ovunque piuttosto che solo in chiamate profondamente annidate). Dato che inizialmente la logica Javascript era piccola e semplice (dopotutto, è solo un'aggiunta a una pagina Web :-), non ci si aspettava che le chiamate di funzione fossero profondamente annidate, quindi un meccanismo try / catch non sembrava necessario.


3
No no no, assolutamente no. I motori così vecchi non contano più per un LUNGO periodo e la comunità javascript in generale è in grado di abbandonare le cose vecchie quando giustificato. Scommetto persino che la maggior parte degli sviluppatori javascript ora sono post-IE6.
Camilo Martin,

0

Credo che non vengano usati così tanto perché il lancio di eccezioni nel codice lato client Javascript rende più difficile il debug di una pagina.

Piuttosto che lanciare eccezioni, generalmente preferisco mostrare una finestra di avviso, (cioè alert("Error, invalid...");)

Potrebbe sembrare strano, ma si verificano errori Javascript sul lato client, se un cliente utilizza una pagina creata e la pagina genera un'eccezione, a meno che il cliente non sia un programmatore esperto di tecnologia, non c'è modo che sarà mai in grado di dirlo tu qual è il problema.

Ti chiamerà solo dicendo: "Ehi, la pagina X non funziona!", E poi dipenderà da te scoprire cosa è andato storto e dove nel codice.

Usando invece la casella di avviso è più probabile che chiami e dica qualcosa del tipo: "Ehi, quando faccio clic sul pulsante A della pagina X mostra una casella che dice ..." , fidati, sarà molto più facile da trovare il bug.

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.