Nu contează cât de mare suntem la programare, uneori scripturile noastre au erori. Acestea pot apărea din cauza greșelilor noastre, a unei intrări neașteptate a utilizatorului, a unui răspuns eronat al serverului și din alte o mie de motive.de obicei, un script „moare” (se oprește imediat) în cazul unei erori, imprimându-l în consolă.
dar există un construct de sintaxă try..catch
care ne permite să” prindem ” erori, astfel încât scriptul să poată, în loc să moară, să facă ceva mai rezonabil.,
„try…catch” sintaxa
try..catch
construirea a două blocuri principale: try
, apoi catch
:
try { // code...} catch (err) { // error handling}
Acesta funcționează ca aceasta:
- în Primul rând, codul în
try {...}
este executat. - Daca nu au existat erori, atunci
catch(err)
este ignorat: executarea ajunge la sfârșitultry
și merge mai departe, sărind pestecatch
., - dacă apare o eroare, atunci execuția
try
este oprită, iar controlul curge la începutulcatch(err)
. Variabilaerr
(putem folosi orice nume pentru aceasta) va conține un obiect de eroare cu detalii despre cele întâmplate.
Deci, o eroare în interiorul try {…}
bloc nu-l omoare pe script – avem o șansă să-l ocupe în catch
.,să ne uităm la câteva exemple.
try..catch
funcționează numai pentru erori de rularePentru try..catch
la locul de muncă, codul trebuie să fie runnable. Cu alte cuvinte, ar trebui să fie JavaScript valid.
nu va funcționa în cazul în care codul este sintactic greșit, de exemplu, are de neegalat acolade:
try { {{{{{{{{{{{{} catch(e) { alert("The engine can't understand this code, it's invalid");}
motor JavaScript mai întâi citește codul, și apoi se ruleaza-l., Erorile care apar în faza de citire se numesc erori „parse-time” și sunt nerecuperabile (din interiorul acelui cod). Asta pentru că motorul nu poate înțelege codul.deci, try..catch
poate gestiona numai Erorile care apar în codul valid. Astfel de erori se numesc „erori de rulare” sau, uneori, „excepții”.
obiect de eroare
când apare o eroare, JavaScript generează un obiect care conține detaliile despre el., Obiectul este apoi transmis ca argument catch
:
try { // ...} catch(err) { // <-- the "error object", could use another word instead of err // ...}
Pentru toate built-in erori, eroarea obiect are două proprietăți principale:
name
Eroare numele. De exemplu, pentru o variabilă nedefinită care este"ReferenceError"
.message
mesaj Textual despre detalii de eroare.
există și alte proprietăți non-standard disponibile în majoritatea mediilor., Unul dintre cele mai utilizate și acceptate este:
stack
stiva de apeluri curente: un șir cu informații despre secvența apelurilor imbricate care au dus la eroare. Folosit în scopuri de depanare.
de exemplu:
opțional” captură ” obligatoriu
Dacă nu avem nevoie de detaliile de eroare, catch
poate omite:
try { // ...} catch { // <-- without (err) // ...}
Utilizarea „try…catch”
Să exploreze viața reală caz de utilizare de try..catch
.
după cum știm deja, JavaScript acceptă JSON.parse (str) metoda pentru a citi valorile codificate JSON.
De obicei este folosit pentru a decoda datele primite prin rețea, de la server sau de la o altă sursă.,
îl primim și apelăm JSON.parse
astfel:
puteți găsi informații mai detaliate despre JSON în metodele JSON, capitolul toJSON.
dacă json
este malformat, JSON.parse
generează o eroare, deci scriptul”moare”.ar trebui să fim mulțumiți de asta? Bineînțeles că nu!în acest fel, dacă ceva nu este în regulă cu datele, vizitatorul nu va ști niciodată acest lucru (cu excepția cazului în care deschide consola dezvoltatorului). Și oamenilor nu le place când ceva „moare” fără niciun mesaj de eroare.,
Să folosim try..catch
să se ocupe de eroare:
Aici vom folosi catch
bloc doar pentru a arăta mesajul, dar putem face mult mai mult: trimite o nouă cerere de rețea, vă propun o alternativă la un vizitator, trimite informații despre o eroare la un exploatarea instalației, … . E mult mai bine decât să mori.
Aruncarea propriile noastre erori
dacă json
este sintactic corect, dar nu au un necesar name
proprietate?,
let json = '{ "age": 30 }'; // incomplete datatry { let user = JSON.parse(json); // <-- no errors alert( user.name ); // no name!} catch (e) { alert( "doesn't execute" );}
Aici JSON.parse
execută în mod normal, dar absența name
este de fapt o eroare pentru noi.
pentru a unifica tratarea erorilor, vom folosi operatorul throw
.
„arunca” operator
throw
operatorul generează o eroare.
sintaxa este:
throw <error object>
tehnic, putem folosi orice ca obiect de eroare., Care ar putea fi chiar un primitiv, cum ar fi un număr sau un șir de caractere, dar este mai bine de a utiliza obiectele, de preferință cu name
și message
properties (să rămână oarecum compatibil cu built-in de erori).
JavaScript are multe built-in de constructori pentru erorile standard: Error
, SyntaxError
, ReferenceError
, TypeError
și altele. Le putem folosi și pentru a crea obiecte de eroare.,
sintaxa Lor este:
let error = new Error(message);// orlet error = new SyntaxError(message);let error = new ReferenceError(message);// ...
Pentru built-in de erori (nu pentru orice obiecte, doar pentru erori), name
proprietatea este exact numele de constructor. Și message
este luat din argument.,
De exemplu:
let error = new Error("Things happen o_O");alert(error.name); // Erroralert(error.message); // Things happen o_O
Să vedem ce fel de eroare JSON.parse
generează:
try { JSON.parse("{ bad json o_O }");} catch(e) { alert(e.name); // SyntaxError alert(e.message); // Unexpected token b in JSON at position 2}
după Cum putem vedea, că e SyntaxError
.
și în cazul nostru, absența name
este eroarea, deoarece utilizatorii trebuie să aibă un name
.,
Deci, haideți să-l arunce:
În linia (*)
, throw
operator generează un SyntaxError
cu message
, la fel ca JavaScript-ar genera în sine. Executarea try
se oprește imediat și fluxul de control sare în catch
.
catch
a devenit un singur loc pentru eroare de manipulare: atât pentru JSON.parse
și alte cazuri.,în exemplul de mai sus folosimtry..catch
pentru a gestiona date incorecte. Dar este posibil să apară o altă eroare neașteptată în blocul try {...}
? Ca o eroare de programare (variabila nu este definită) sau altceva, nu doar acest lucru „date incorecte”.
de exemplu:
desigur, totul este posibil! Programatorii fac greșeli. Chiar și în utilitățile open-source folosite de milioane de zeci de ani – dintr-o dată poate fi descoperită o eroare care duce la hack-uri teribile.,
În cazul nostru, try..catch
este plasat pentru a prinde Erorile „date incorecte”. Dar, prin natura sa, catch
primește toate erorile de la try
. Aici apare o eroare neașteptată, dar arată același mesaj "JSON Error"
. Acest lucru este greșit și, de asemenea, face Codul mai dificil de depanat.pentru a evita astfel de probleme, putem folosi tehnica „rethrowing”. Regula este simplă:
captura ar trebui să proceseze doar erorile pe care le cunoaște și să „regândească” toate celelalte.,tehnica „rethrowing” poate fi explicată mai detaliat ca:
- captura primește toate erorile.
- în blocul
catch(err) {...}
analizăm obiectul de eroareerr
. - dacă nu știm cum să ne descurcăm, facem
throw err
.
de Obicei, putem verifica tipul de eroare folosind instanceof
operator:
putem obține, de asemenea, eroare de numele clasei din err.name
proprietate. Toate erorile native o au. O altă opțiune este să citiți err.constructor.name
.,
În codul de mai jos, vom folosi rethrowing astfel încât catch
numai mânere SyntaxError
:
eroare aruncat pe linia (*)
din interiorul catch
bloc „cade” de try..catch
și poate fi prins printr-un exterior try..catch
construct (dacă există), sau ucide script.
deci blocul catch
gestionează de fapt numai erorile cu care știe să se ocupe și „omite” toate celelalte.,
exemplu de mai jos demonstrează cum un astfel de erori poate fi prins de un nivel mai mult de try..catch
:
Aici readData
știe doar cum să se ocupe de SyntaxError
, în timp ce exterior try..catch
știe cum să se ocupe de tot.
încercați … prinde … în cele din urmă
așteptați, asta nu e tot.
construcția try..catch
poate avea încă o clauză de cod: finally
.,
Dacă există, se execută în toate cazurile:
- dupa
try
, daca nu au existat erori, - dupa
catch
, dacă nu au fost erori.
extinse sintaxa arată astfel:
try { ... try to execute the code ...} catch(e) { ... handle errors ...} finally { ... execute always ...}
Încercați să rulați acest cod:
try { alert( 'try' ); if (confirm('Make an error?')) BAD_CODE();} catch (e) { alert( 'catch' );} finally { alert( 'finally' );}
cod are două moduri de execuție:
- Dacă ai răspuns „Da” la „a Face o eroare?”, apoi
try -> catch -> finally
., - dacă spui „nu”, atunci
try -> finally
.
clauzafinally
este adesea folosită atunci când începem să facem ceva și dorim să-l finalizăm în orice caz de rezultat.
de exemplu, vrem să măsurăm timpul în care o funcție de numere Fibonacci fib(n)
ia. Desigur, putem începe măsurarea înainte de a rula și termina după aceea. Dar dacă există o eroare în timpul apelului de funcții? În special, implementarea fib(n)
în codul de mai jos returnează o eroare pentru numere negative sau non-întregi.,
clauzafinally
este un loc minunat pentru a termina măsurătorile indiferent de situație.
Aici finally
garantează că timpul va fi măsurat în mod corect, în ambele situații – în caz de o execuție de succes fib
și în caz de o eroare în ea:
puteți verifica prin rularea de cod cu intrarea 35
în prompt
– se execută în mod normal, finally
dupa try
., Și apoi introduceți -1
– nu va fi o eroare imediată, iar execuția va dura 0ms
. Ambele măsurători sunt efectuate corect.
cu alte cuvinte, funcția se poate termina cu return
sau throw
, asta nu contează. Clauza finally
se execută în ambele cazuri.,
try..catch..finally
vă Rugăm să rețineți că result
și diff
variabile în codul de mai sus sunt declarate înainte try..catch
.
în caz Contrar, dacă ne-am declarat let
în try
bloc, ar fi vizibile numai în interiorul de ea.
try..finally
try..finally
construct, fără catch
clauză, este, de asemenea, util., Îl aplicăm atunci când nu vrem să gestionăm Erorile aici (lăsați-le să cadă), dar vrem să fim siguri că procesele pe care le-am început sunt finalizate.
function func() { // start doing something that needs completion (like measurements) try { // ... } finally { // complete that thing even if all dies }}
În codul de mai sus, o eroare interior try
mereu cade, pentru că nu e catch
. Dar finally
funcționează înainte ca fluxul de execuție să părăsească funcția.
captură globală
informațiile din această secțiune nu fac parte din JavaScript-ul de bază.,
să ne imaginăm că avem o eroare fatală în afara try..catch
, iar scenariul a murit. Ca o eroare de programare sau un alt lucru teribil.există o modalitate de a reacționa la astfel de evenimente? Este posibil să dorim să înregistrăm eroarea, să arătăm ceva utilizatorului (în mod normal nu văd mesaje de eroare) etc.
nu există niciunul în specificație, dar mediile îl oferă de obicei, deoarece este cu adevărat util. De exemplu, nod.js are process.on("uncaughtException")
pentru asta. Și în browser putem atribui o funcție ferestrei speciale.,onerror proprietate, care va rula în cazul unei erori neprins.
sintaxa:
window.onerror = function(message, url, line, col, error) { // ...};
message
mesaj de Eroare.url
URL-ul scriptului unde s-a produs eroarea.line
,col
numere de linie și coloană unde s-a produs eroarea.error
obiect de eroare.,
De exemplu:
rolul global handler window.onerror
este, de obicei, nu pentru a recupera executarea script – probabil că e imposibil în cazul unei erori de programare, ci de a trimite mesaj de eroare pentru dezvoltatori.
funcționează astfel:
- ne înregistrăm la serviciu și obținem o bucată de JS (sau un URL de script) de la ei pentru a le insera pe pagini.
- că JS script stabilește un obicei
window.onerror
funcție. - când apare o eroare, trimite o solicitare de rețea despre aceasta serviciului.
- ne putem conecta la interfața web a serviciului și putem vedea erori.,
rezumat
try..catch
construct permite să se ocupe de erori de execuție. Acesta permite literalmente să” încercați „rularea codului și să” prindeți ” Erorile care pot apărea în el.
sintaxa este:
nu poate fi nici catch
secțiunea sau nu finally
, deci mai scurt constructe try..catch
și try..finally
sunt, de asemenea, valabil.
obiectele de eroare au următoarele proprietăți:
-
message
– mesajul de eroare care poate fi citit de om., -
name
– șirul cu nume de eroare (nume constructor de eroare). -
stack
(non-standard, dar bine acceptat)-stiva în momentul creării erorii.
Dacă o eroare obiect nu este necesar, putem omite folosind catch {
în loc de catch(err) {
.de asemenea, putem genera propriile erori folosind operatorul throw
., Din punct de vedere tehnic, argumentul throw
poate fi orice, dar de obicei e o eroare obiect moștenirea de la built-in Error
clasa. Mai multe despre extinderea erorilor în capitolul următor.
Rethrowing este un foarte important model de eroare de manipulare: un catch
bloc, de obicei, se așteaptă și știe cum să se ocupe în special de tip eroare, așa că ar trebui să rethrow erori nu știu.chiar dacă nu avem try..catch
, majoritatea mediilor ne permit să configurăm un handler de erori „global” pentru a detecta erorile care „cad”., În browser, este window.onerror
.