Un ghid definitiv pentru gestionarea erorilor în JavaScript
Publicat: 2022-01-24Legea lui Murphy spune că orice poate merge prost în cele din urmă va merge prost. Acest lucru se aplică puțin prea bine în lumea programării. Dacă creați o aplicație, sunt șanse să creați erori și alte probleme. Erorile în JavaScript sunt una dintre problemele comune!
Succesul unui produs software depinde de cât de bine pot rezolva aceste probleme creatorii săi înainte de a-și răni utilizatorii. Și JavaScript, dintre toate limbajele de programare, este renumit pentru designul său mediu de gestionare a erorilor.
Dacă construiți o aplicație JavaScript, există șanse mari să faceți greșeli cu tipurile de date la un moment dat. Dacă nu, atunci s-ar putea să înlocuiți un operator nedefinit cu un operator nul sau triplu egal ( ===
) cu un operator dublu egal ( ==
).
Este uman doar să faci greșeli. Acesta este motivul pentru care vă vom arăta tot ce trebuie să știți despre gestionarea erorilor în JavaScript.
Acest articol vă va ghida prin erorile de bază din JavaScript și vă va explica diferitele erori pe care le puteți întâlni. Veți învăța apoi cum să identificați și să remediați aceste erori. Există, de asemenea, câteva sfaturi pentru a gestiona eficient erorile în mediile de producție.
Fără alte prelungiri, să începem!
Ce sunt erorile JavaScript?
Erorile de programare se referă la situații care nu permit unui program să funcționeze normal. Se poate întâmpla atunci când un program nu știe cum să se ocupe de sarcina la îndemână, cum ar fi când încearcă să deschidă un fișier inexistent sau când ajunge la un punct final API bazat pe web, în timp ce nu există conectivitate la rețea.
Aceste situații împing programul să arunce erori utilizatorului, afirmând că nu știe cum să procedeze. Programul colectează cât mai multe informații despre eroare și apoi raportează că nu poate merge mai departe.
Programatorii inteligenți încearcă să prezică și să acopere aceste scenarii, astfel încât utilizatorul să nu fie nevoit să descopere un mesaj de eroare tehnică precum „404” în mod independent. În schimb, afișează un mesaj mult mai ușor de înțeles: „Pagina nu a putut fi găsită”.
Erorile din JavaScript sunt obiecte afișate ori de câte ori apare o eroare de programare. Aceste obiecte conțin informații ample despre tipul erorii, declarația care a cauzat eroarea și trasarea stivei când a apărut eroarea. JavaScript permite, de asemenea, programatorilor să creeze erori personalizate pentru a oferi informații suplimentare atunci când problemele de depanare.
Proprietățile unei erori
Acum că definiția unei erori JavaScript este clară, este timpul să ne aruncăm în detalii.
Erorile din JavaScript poartă anumite proprietăți standard și personalizate care ajută la înțelegerea cauzei și efectelor erorii. În mod implicit, erorile din JavaScript conțin trei proprietăți:
- mesaj : O valoare șir care poartă mesajul de eroare
- nume : tipul de eroare care a apărut (ne vom aprofunda în această secțiune în secțiunea următoare)
- stack : Urmărirea stivei a codului executat atunci când a apărut eroarea.
În plus, erorile pot avea și proprietăți precum columnNumber, lineNumber, fileName etc., pentru a descrie mai bine eroarea. Cu toate acestea, aceste proprietăți nu sunt standard și pot fi prezente sau nu în fiecare obiect de eroare generat din aplicația dvs. JavaScript.
Înțelegerea Stack Trace
O urmărire a stivei este lista apelurilor de metodă în care se afla un program atunci când are loc un eveniment, cum ar fi o excepție sau un avertisment. Iată cum arată un exemplu de urmărire a stivei însoțită de o excepție:

După cum puteți vedea, începe prin a tipări numele și mesajul erorii, urmate de o listă de metode care au fost apelate. Fiecare apel de metodă indică locația codului sursă și linia la care a fost invocat. Puteți utiliza aceste date pentru a naviga prin baza de cod și a identifica ce fragment de cod cauzează eroarea.
Această listă de metode este aranjată într-un mod stivuit. Arată unde a fost lansată prima excepție și cum s-a propagat prin apelurile de metodă stivuite. Implementarea unui catch pentru excepție nu o va permite să se propagă prin stivă și să vă blocheze programul. Cu toate acestea, este posibil să doriți să lăsați erorile fatale neprinse pentru a bloca programul în mod intenționat în unele scenarii.
Erori vs Excepții
Majoritatea oamenilor consideră de obicei erorile și excepțiile ca fiind același lucru. Cu toate acestea, este esențial să remarcăm o diferență ușoară, dar fundamentală între ele.
Pentru a înțelege mai bine acest lucru, să luăm un exemplu rapid. Iată cum puteți defini o eroare în JavaScript:
const wrongTypeError = TypeError("Wrong type found, expected character")
Și acesta este modul în care obiectul wrongTypeError
devine o excepție:
throw wrongTypeError
Cu toate acestea, majoritatea oamenilor tind să folosească forma scurtă care definește obiectele de eroare în timp ce le aruncă:
throw TypeError("Wrong type found, expected character")
Aceasta este o practică standard. Cu toate acestea, acesta este unul dintre motivele pentru care dezvoltatorii tind să amestece excepțiile și erorile. Prin urmare, cunoașterea elementelor fundamentale este vitală, chiar dacă folosiți stenografie pentru a vă termina rapid munca.
Tipuri de erori în JavaScript
Există o serie de tipuri de erori predefinite în JavaScript. Ele sunt alese și definite automat de runtime JavaScript ori de câte ori programatorul nu gestionează în mod explicit erorile din aplicație.
Această secțiune vă va ghida prin unele dintre cele mai frecvente tipuri de erori în JavaScript și va înțelege când și de ce apar.
RangeError
O RangeError este aruncată atunci când o variabilă este setată cu o valoare în afara intervalului de valori legale. De obicei, apare atunci când se transmite o valoare ca argument unei funcții, iar valoarea dată nu se află în intervalul parametrilor funcției. Uneori poate deveni dificil de remediat atunci când utilizați biblioteci terță parte prost documentate, deoarece trebuie să cunoașteți intervalul de valori posibile pentru ca argumentele să treacă în valoarea corectă.
Unele dintre scenariile comune în care apare RangeError sunt:
- Încercarea de a crea o matrice de lungimi ilegale prin constructorul Array.
- Transmiterea de valori greșite la metode numerice precum
toExponential()
,toPrecision()
,toFixed()
etc. - Transmiterea valorilor ilegale la funcții șir precum
normalize()
.
ReferenceError
O ReferenceError apare atunci când ceva este în neregulă cu referința unei variabile din codul dvs. S-ar putea să fi uitat să definiți o valoare pentru variabilă înainte de a o folosi sau s-ar putea să încercați să utilizați o variabilă inaccesibilă în codul dvs. În orice caz, trecerea prin urmărirea stivei oferă informații ample pentru a găsi și a remedia referința variabilă care este defectă.
Unele dintre motivele comune pentru care apar ReferenceErrors sunt:
- Efectuarea unei greșeli de tipar într-un nume de variabilă.
- Încercarea de a accesa variabilele blocate în afara domeniului lor.
- Referința la o variabilă globală dintr-o bibliotecă externă (cum ar fi $ din jQuery) înainte de a fi încărcată.
Eroare de sintaxă
Aceste erori sunt una dintre cele mai simple de remediat, deoarece indică o eroare în sintaxa codului. Deoarece JavaScript este un limbaj de scripting care este interpretat mai degrabă decât compilat, acestea sunt aruncate atunci când aplicația execută scriptul care conține eroarea. În cazul limbilor compilate, astfel de erori sunt identificate în timpul compilării. Astfel, binarele aplicației nu sunt create până când acestea nu sunt remediate.
Unele dintre motivele comune pentru care pot apărea SyntaxErrors sunt:
- Lipsesc virgulele inversate
- Lipsesc parantezele de închidere
- Alinierea necorespunzătoare a acoladelor sau a altor caractere
Este o practică bună să utilizați un instrument de listing în IDE-ul dvs. pentru a identifica astfel de erori înainte ca acestea să ajungă în browser.
Eroare de scris
TypeError este una dintre cele mai frecvente erori în aplicațiile JavaScript. Această eroare este creată atunci când o anumită valoare nu se dovedește a fi de un anumit tip așteptat. Unele dintre cazurile frecvente când apare sunt:
- Invocarea obiectelor care nu sunt metode.
- Încercarea de a accesa proprietățile obiectelor nule sau nedefinite
- Tratarea unui șir ca număr sau invers
Există mult mai multe posibilități în care poate apărea o TypeError. Ne vom uita la câteva cazuri celebre mai târziu și vom afla cum să le remediam.
Eroare internă
Tipul InternalError este utilizat atunci când apare o excepție în motorul de rulare JavaScript. Poate indica sau nu o problemă cu codul dvs.
De cele mai multe ori, InternalError apare numai în două scenarii:
- Când un patch sau o actualizare a runtime JavaScript poartă o eroare care generează excepții (acest lucru se întâmplă foarte rar)
- Când codul tău conține entități care sunt prea mari pentru motorul JavaScript (de exemplu, prea multe cazuri de comutare, inițializatoare de matrice prea mari, prea multă recursivitate)
Cea mai potrivită abordare pentru a rezolva această eroare este identificarea cauzei prin mesajul de eroare și restructurarea logicii aplicației, dacă este posibil, pentru a elimina creșterea bruscă a sarcinii de lucru pe motorul JavaScript.
URIeroare
URIErorea apare atunci când o funcție globală de gestionare a URI, cum ar fi decodeURIComponent
, este utilizată ilegal. De obicei, indică faptul că parametrul transmis apelului de metodă nu a fost conform standardelor URI și, prin urmare, nu a fost analizat de metodă în mod corespunzător.
Diagnosticarea acestor erori este de obicei ușoară, deoarece trebuie doar să examinați argumentele pentru malformație.
EvalError
O EvalError apare atunci când apare o eroare la apelul funcției eval()
. Funcția eval()
este folosită pentru a executa codul JavaScript stocat în șiruri de caractere. Cu toate acestea, deoarece utilizarea funcției eval()
este foarte descurajată din cauza problemelor de securitate și specificațiile actuale ECMAScript nu mai aruncă clasa EvalError
, acest tip de eroare există pur și simplu pentru a menține compatibilitatea cu codul JavaScript moștenit.
Dacă lucrați la o versiune mai veche de JavaScript, este posibil să întâmpinați această eroare. În orice caz, cel mai bine este să investigați codul executat în apelul funcției eval()
pentru orice excepții.
Crearea unor tipuri de erori personalizate
Deși JavaScript oferă o listă adecvată de clase de tip de eroare pentru a acoperi majoritatea scenariilor, puteți oricând să creați un nou tip de eroare dacă lista nu vă satisface cerințele. Fundamentul acestei flexibilități constă în faptul că JavaScript vă permite să aruncați orice cu comanda throw
.
Deci, din punct de vedere tehnic, aceste declarații sunt în întregime legale:
throw 8 throw "An error occurred"
Cu toate acestea, aruncarea unui tip de date primitiv nu oferă detalii despre eroare, cum ar fi tipul, numele sau urmărirea stivei însoțitoare. Pentru a remedia acest lucru și a standardiza procesul de tratare a erorilor, a fost furnizată clasa Error
. De asemenea, este descurajat să folosiți tipuri de date primitive în timp ce aruncați excepții.
Puteți extinde clasa Error
pentru a crea clasa dvs. de eroare personalizată. Iată un exemplu de bază despre cum puteți face acest lucru:
class ValidationError extends Error { constructor(message) { super(message); this.name = "ValidationError"; } }
Și îl puteți folosi în felul următor:
throw ValidationError("Property not found: name")
Și apoi îl puteți identifica folosind cuvântul cheie instanceof
:
try { validateForm() // code that throws a ValidationError } catch (e) { if (e instanceof ValidationError) // do something else // do something else }
Top 10 cele mai frecvente erori în JavaScript
Acum că înțelegeți tipurile obișnuite de erori și cum să le creați pe cele personalizate, este timpul să vă uitați la unele dintre cele mai frecvente erori cu care vă veți confrunta când scrieți codul JavaScript.
1. RangeError neprins
Această eroare apare în Google Chrome în câteva scenarii diferite. În primul rând, se poate întâmpla dacă apelați o funcție recursivă și aceasta nu se termină. Puteți verifica acest lucru singur în Consola pentru dezvoltatori Chrome:

Deci, pentru a rezolva o astfel de eroare, asigurați-vă că definiți corect cazurile de frontieră ale funcției dvs. recursive. Un alt motiv pentru care apare această eroare este dacă ați trecut o valoare care este în afara intervalului de parametru al unei funcții. Iată un exemplu:

Mesajul de eroare va indica de obicei ce este în neregulă cu codul dvs. Odată ce faceți modificările, acestea vor fi rezolvate.

2. Uncaught TypeError: Nu se poate seta proprietatea
Această eroare apare atunci când setați o proprietate pe o referință nedefinită. Puteți reproduce problema cu acest cod:
var list list.count = 0
Iată rezultatul pe care îl veți primi:

Pentru a remedia această eroare, inițializați referința cu o valoare înainte de a accesa proprietățile acesteia. Iată cum arată când este reparat:

3. Eroare de tip neprins: Proprietatea nu poate fi citită
Aceasta este una dintre erorile cele mai frecvente în JavaScript. Această eroare apare atunci când încercați să citiți o proprietate sau să apelați o funcție pe un obiect nedefinit. Îl puteți reproduce foarte ușor rulând următorul cod într-o consolă pentru dezvoltatori Chrome:
var func func.call()
Iată rezultatul:

Un obiect nedefinit este una dintre numeroasele cauze posibile ale acestei erori. O altă cauză proeminentă a acestei probleme poate fi o inițializare necorespunzătoare a stării în timpul redării interfeței de utilizare. Iată un exemplu real dintr-o aplicație React:
import React, { useState, useEffect } from "react"; const CardsList = () => { const [state, setState] = useState(); useEffect(() => { setTimeout(() => setState({ items: ["Card 1", "Card 2"] }), 2000); }, []); return ( <> {state.items.map((item) => ( <li key={item}>{item}</li> ))} </> ); }; export default CardsList;
Aplicația începe cu un container de stare gol și este furnizată cu unele articole după o întârziere de 2 secunde. Întârzierea este pusă în aplicare pentru a imita un apel de rețea. Chiar dacă rețeaua ta este super rapidă, te vei confrunta în continuare cu o întârziere minoră din cauza căreia componenta va fi randată cel puțin o dată. Dacă încercați să rulați această aplicație, veți primi următoarea eroare:

Acest lucru se datorează faptului că, la momentul redării, containerul de stare este nedefinit; astfel, nu există items
de proprietate pe el. Remedierea acestei erori este ușoară. Trebuie doar să furnizați o valoare implicită inițială containerului de stare.
// ... const [state, setState] = useState({items: []}); // ...
Acum, după întârzierea setată, aplicația dvs. va afișa o ieșire similară:

Remedierea exactă din codul dvs. ar putea fi diferită, dar esența aici este să vă inițializați întotdeauna variabilele în mod corespunzător înainte de a le folosi.
4. TypeError: „undefined” nu este un obiect
Această eroare apare în Safari atunci când încercați să accesați proprietățile sau să apelați o metodă pe un obiect nedefinit. Puteți rula același cod de mai sus pentru a reproduce singur eroarea.

Soluția la această eroare este, de asemenea, aceeași - asigurați-vă că ați inițializat corect variabilele și că nu sunt nedefinite atunci când este accesată o proprietate sau o metodă.
5. TypeError: null nu este un obiect
Aceasta este, din nou, similară cu eroarea anterioară. Apare pe Safari și singura diferență dintre cele două erori este că aceasta este aruncată atunci când obiectul a cărui proprietate sau metodă este accesată este null
în loc de undefined
. Puteți reproduce acest lucru rulând următoarea bucată de cod:
var func = null func.call()
Iată rezultatul pe care îl veți primi:

Deoarece null
este o valoare setată în mod explicit unei variabile și nu este atribuită automat de JavaScript. Această eroare poate apărea numai dacă încercați să accesați o variabilă pe care ați setat-o singur null
. Deci, trebuie să vă revizuiți codul și să verificați dacă logica pe care ați scris-o este corectă sau nu.
6. TypeError: Nu se poate citi proprietatea „lungime”
Această eroare apare în Chrome când încercați să citiți lungimea unui obiect null
sau undefined
. Cauza acestei probleme este similară cu problemele anterioare, dar apare destul de frecvent în timpul manipulării listelor; prin urmare, merită o mențiune specială. Iată cum puteți reproduce problema:

Cu toate acestea, în versiunile mai noi de Chrome, această eroare este raportată ca Uncaught TypeError: Cannot read properties of undefined
. Asa arata acum:

Remedierea, din nou, este să vă asigurați că obiectul a cărui lungime încercați să o accesați există și nu este setat la null
.
7. TypeError: „undefined” nu este o funcție
Această eroare apare atunci când încercați să invocați o metodă care nu există în script-ul dvs. sau o face, dar nu poate fi referită în contextul apelării. Această eroare apare de obicei în Google Chrome și o puteți rezolva verificând linia de cod care aruncă eroarea. Dacă găsiți o greșeală de tipar, remediați-o și verificați dacă vă rezolvă problema.
Dacă ați folosit cuvântul cheie de auto-referință this
în codul dvs., această eroare poate apărea dacă this
nu este legată în mod corespunzător de contextul dvs. Luați în considerare următorul cod:
function showAlert() { alert("message here") } document.addEventListener("click", () => { this.showAlert(); })
Dacă executați codul de mai sus, va arunca eroarea despre care am discutat. Se întâmplă deoarece funcția anonimă transmisă ca ascultător de evenimente este executată în contextul document
.
În schimb, funcția showAlert
este definită în contextul window
.
Pentru a rezolva acest lucru, trebuie să transmiteți referința adecvată funcției legând-o cu metoda bind()
:
document.addEventListener("click", this.showAlert.bind(this))
8. ReferenceError: evenimentul nu este definit
Această eroare apare atunci când încercați să accesați o referință nedefinită în domeniul de apelare. Acest lucru se întâmplă de obicei atunci când gestionați evenimente, deoarece acestea vă oferă adesea o referință numită event
în funcția de apel invers. Această eroare poate apărea dacă uitați să definiți argumentul evenimentului în parametrii funcției dvs. sau să îl scrieți greșit.
Este posibil ca această eroare să nu apară în Internet Explorer sau Google Chrome (deoarece IE oferă o variabilă de eveniment globală și Chrome atașează automat variabila de eveniment la handler), dar poate apărea în Firefox. Așa că este indicat să fii cu ochii pe astfel de mici greșeli.

9. TypeError: Atribuire la variabila constantă
Aceasta este o eroare care apare din neatenție. Dacă încercați să atribuiți o nouă valoare unei variabile constante, veți primi un astfel de rezultat:

Deși pare ușor de remediat acum, imaginați-vă sute de astfel de declarații variabile și una dintre ele definită în mod eronat ca const
în loc de let
! Spre deosebire de alte limbaje de scripting precum PHP, există o diferență minimă între stilul de declarare a constantelor și variabilelor în JavaScript. Prin urmare, este recomandabil să vă verificați declarațiile în primul rând atunci când vă confruntați cu această eroare. De asemenea, puteți întâlni această eroare dacă uitați că referința menționată este o constantă și o utilizați ca variabilă. Acest lucru indică fie neatenție, fie un defect în logica aplicației dvs. Asigurați-vă că verificați acest lucru atunci când încercați să remediați această problemă.
10. (necunoscut): Eroare de script
O eroare de script apare atunci când un script terță parte trimite o eroare browserului dvs. Această eroare este urmată de (necunoscut) deoarece scriptul terță parte aparține unui alt domeniu decât aplicația dvs. Browserul ascunde alte detalii pentru a preveni scurgerea de informații sensibile din scriptul terță parte.
Nu puteți rezolva această eroare fără a cunoaște detaliile complete. Iată ce puteți face pentru a obține mai multe informații despre eroare:
- Adăugați atributul
crossorigin
în eticheta de script. - Setați antetul corect
Access-Control-Allow-Origin
pe serverul care găzduiește scriptul. - [Opțional] Dacă nu aveți acces la serverul care găzduiește scriptul, puteți lua în considerare utilizarea unui proxy pentru a vă transmite cererea către server și înapoi către client cu anteturile corecte.
Odată ce puteți accesa detaliile erorii, vă puteți configura apoi pentru a remedia problema, care va fi probabil fie cu biblioteca terță parte, fie cu rețea.
Cum să identificați și să preveniți erorile în JavaScript
În timp ce erorile discutate mai sus sunt cele mai comune și frecvente în JavaScript, veți întâlni, bazarea pe câteva exemple nu poate fi niciodată suficientă. Este vital să înțelegeți cum să detectați și să preveniți orice tip de eroare într-o aplicație JavaScript în timpul dezvoltării acesteia. Iată cum puteți gestiona erorile în JavaScript.
Erori de aruncare și prindeți manual
Cea mai fundamentală modalitate de a gestiona erorile care au fost aruncate fie manual, fie de către timpul de execuție este de a le detecta. La fel ca majoritatea altor limbi, JavaScript oferă un set de cuvinte cheie pentru a gestiona erorile. Este esențial să le cunoașteți în profunzime pe fiecare dintre ele înainte de a vă stabili să gestionați erorile din aplicația JavaScript.
arunca
Primul și cel mai de bază cuvânt cheie al setului este throw
. După cum este evident, cuvântul cheie throw este folosit pentru a arunca erori pentru a crea manual excepții în timpul de execuție JavaScript. Am discutat deja despre acest lucru mai devreme în articol și iată esenta semnificației acestui cuvânt cheie:
- Puteți
throw
orice, inclusiv numere, șiruri și obiecteError
. - Cu toate acestea, nu este recomandabil să aruncați tipuri de date primitive, cum ar fi șiruri de caractere și numere, deoarece acestea nu conțin informații de depanare despre erori.
- Exemplu:
throw TypeError("Please provide a string")
încerca
Cuvântul cheie try
este folosit pentru a indica faptul că un bloc de cod ar putea arunca o excepție. Sintaxa sa este:
try { // error-prone code here }
Este important să rețineți că un bloc catch
trebuie să urmeze întotdeauna blocul try
pentru a gestiona erorile în mod eficient.
captură
Cuvântul cheie catch
este folosit pentru a crea un bloc catch. Acest bloc de cod este responsabil pentru gestionarea erorilor pe care le detectează blocul de try
finală. Iată sintaxa acesteia:
catch (exception) { // code to handle the exception here }
Și așa implementați blocurile try
și catch
împreună:
try { // business logic code } catch (exception) { // error handling code }
Spre deosebire de C++ sau Java, nu puteți adăuga mai multe blocuri catch
la un bloc try
în JavaScript. Aceasta înseamnă că nu poți face asta:
try { // business logic code } catch (exception) { if (exception instanceof TypeError) { // do something } } catch (exception) { if (exception instanceof RangeError) { // do something } }
În schimb, puteți utiliza o instrucțiune if...else
sau o instrucțiune switch case în interiorul blocului unic catch pentru a gestiona toate cazurile de eroare posibile. Ar arata asa:
try { // business logic code } catch (exception) { if (exception instanceof TypeError) { // do something } else if (exception instanceof RangeError) { // do something else } }
in cele din urma
Cuvântul cheie finally
este folosit pentru a defini un bloc de cod care este rulat după ce o eroare a fost tratată. Acest bloc este executat după blocurile try și catch.
De asemenea, blocul final va fi executat indiferent de rezultatul celorlalte două blocuri. Aceasta înseamnă că, chiar dacă blocul catch nu poate gestiona eroarea în întregime sau o eroare este aruncată în blocul catch, interpretul va executa codul în blocul final înainte ca programul să se blocheze.
Pentru a fi considerat valid, blocul try din JavaScript trebuie urmat fie de un blocaj catch, fie de un bloc final. Fără oricare dintre acestea, interpretul va genera o SyntaxError. Prin urmare, asigurați-vă că urmați blocurile de încercare cu cel puțin oricare dintre ele atunci când gestionați erorile.
Gestionați erorile la nivel global cu metoda onerror().
Metoda onerror()
este disponibilă pentru toate elementele HTML pentru a gestiona orice erori care pot apărea cu acestea. De exemplu, dacă o etichetă img
nu poate găsi imaginea a cărei adresă URL este specificată, își lansează metoda onerror pentru a permite utilizatorului să gestioneze eroarea.
De obicei, ați furniza o altă adresă URL a imaginii în apelul onerror la care să se întoarcă eticheta img
. Iată cum puteți face asta prin JavaScript:
const image = document.querySelector("img") image.onerror = (event) => { console.log("Error occurred: " + event) }
Cu toate acestea, puteți utiliza această funcție pentru a crea un mecanism global de gestionare a erorilor pentru aplicația dvs. Iată cum o poți face:
window.onerror = (event) => { console.log("Error occurred: " + event) }
Cu acest handler de evenimente, puteți scăpa de mai multe try...catch
blocurile care se află în codul dvs. și puteți centraliza gestionarea erorilor aplicației dvs. similar cu gestionarea evenimentelor. Puteți atașa mai multe soluții de gestionare a erorilor la fereastră pentru a menține principiul responsabilității unice din principiile de proiectare SOLID. Interpretul va parcurge toate manevrele până când ajunge pe cel potrivit.
Transmite erori prin apeluri inverse
În timp ce funcțiile simple și liniare permit gestionarea erorilor să rămână simplă, apelurile inverse pot complica afacerea.
Luați în considerare următoarea bucată de cod:
Aveți nevoie de o soluție de găzduire care să vă ofere un avantaj competitiv? Kinsta v-a acoperit cu o viteză incredibilă, securitate de ultimă generație și scalare automată. Verificați planurile noastre
const calculateCube = (number, callback) => { setTimeout(() => { const cube = number * number * number callback(cube) }, 1000) } const callback = result => console.log(result) calculateCube(4, callback)
Funcția de mai sus demonstrează o condiție asincronă în care o funcție durează ceva timp pentru a procesa operațiuni și returnează rezultatul mai târziu cu ajutorul unui apel invers.
Dacă încercați să introduceți un șir în loc de 4 în apelul de funcție, veți obține NaN
ca rezultat.
Acest lucru trebuie tratat corect. Iată cum:
const calculateCube = (number, callback) => { setTimeout(() => { if (typeof number !== "number") throw new Error("Numeric argument is expected") const cube = number * number * number callback(cube) }, 1000) } const callback = result => console.log(result) try { calculateCube(4, callback) } catch (e) { console.log(e) }
Acest lucru ar trebui să rezolve problema în mod ideal. Cu toate acestea, dacă încercați să treceți un șir apelului de funcție, veți primi acest lucru:

Chiar dacă ați implementat un bloc try-catch în timp ce apelați funcția, tot spune că eroarea nu este prinsă. Eroarea este aruncată după ce blocul catch a fost executat din cauza întârzierii timeout.
Acest lucru se poate întâmpla rapid în apelurile în rețea, unde se strecoară întârzieri neașteptate. Trebuie să acoperiți astfel de cazuri în timp ce vă dezvoltați aplicația.
Iată cum puteți gestiona corect erorile în apeluri inverse:
const calculateCube = (number, callback) => { setTimeout(() => { if (typeof number !== "number") { callback(new TypeError("Numeric argument is expected")) return } const cube = number * number * number callback(null, cube) }, 2000) } const callback = (error, result) => { if (error !== null) { console.log(error) return } console.log(result) } try { calculateCube('hey', callback) } catch (e) { console.log(e) }
Acum, ieșirea la consolă va fi:

Aceasta indică faptul că eroarea a fost tratată în mod corespunzător.
Gestionați erorile din promisiuni
Majoritatea oamenilor tind să prefere promisiunile pentru gestionarea activităților asincrone. Promisiunile au un alt avantaj – o promisiune respinsă nu termină scriptul tău. Cu toate acestea, trebuie să implementați un bloc catch pentru a gestiona erorile din promisiuni. Pentru a înțelege mai bine acest lucru, să rescriem funcția calculateCube()
folosind Promises:
const delay = ms => new Promise(res => setTimeout(res, ms)); const calculateCube = async (number) => { if (typeof number !== "number") throw Error("Numeric argument is expected") await delay(5000) const cube = number * number * number return cube } try { calculateCube(4).then(r => console.log(r)) } catch (e) { console.log(e) }
Timeout-ul din codul anterior a fost izolat în funcția de delay
pentru înțelegere. Dacă încercați să introduceți un șir în loc de 4, rezultatul pe care îl obțineți va fi similar cu acesta:

Din nou, acest lucru se datorează faptului că Promise
a aruncat eroarea după ce totul s-a finalizat. Soluția la această problemă este simplă. Pur și simplu adăugați un apel catch()
la lanțul de promisiuni astfel:
calculateCube("hey") .then(r => console.log(r)) .catch(e => console.log(e))
Acum rezultatul va fi:

Puteți observa cât de ușor este să gestionați erorile cu promisiuni. În plus, puteți înlănțui un bloc finally()
și apelul de promisiune pentru a adăuga cod care va rula după finalizarea procesării erorilor.
Alternativ, puteți gestiona erorile din promisiuni folosind tehnica tradițională try-catch-finally. Iată cum ar arăta apelul de promisiune în acest caz:
try { let result = await calculateCube("hey") console.log(result) } catch (e) { console.log(e) } finally { console.log('Finally executed") }
Cu toate acestea, aceasta funcționează numai în cadrul unei funcții asincrone. Prin urmare, cel mai preferat mod de a gestiona erorile din promisiuni este de a înlănțui catch
și, finally
, de a apela la promisiuni.
throw/catch vs onerror() vs Callbacks vs Promises: Care este cel mai bun?
Cu patru metode la dispoziție, trebuie să știi să alegi cea mai potrivită în orice caz de utilizare dat. Iată cum puteți decide singuri:
arunca/prinde
Veți folosi această metodă de cele mai multe ori. Asigurați-vă că implementați condiții pentru toate erorile posibile în blocul dvs. catch și nu uitați să includeți un bloc final dacă trebuie să rulați niște rutine de curățare a memoriei după blocul try.
Cu toate acestea, prea multe blocuri try/catch pot face codul dificil de întreținut. Dacă vă aflați într-o astfel de situație, este posibil să doriți să gestionați erorile prin gestionarea globală sau prin metoda promisiunii.
Când decideți între blocurile asincrone try/catch și promise's catch()
, este recomandabil să mergeți cu blocurile asincrone try/catch, deoarece acestea vă vor face codul liniar și ușor de depanat.
onerror()
Cel mai bine este să utilizați metoda onerror()
când știți că aplicația dvs. trebuie să gestioneze multe erori și acestea pot fi bine împrăștiate în întreaga bază de cod. Metoda onerror
vă permite să gestionați erorile ca și cum ar fi doar un alt eveniment gestionat de aplicația dvs. Puteți defini mai mulți gestionatori de erori și îi puteți atașa la fereastra aplicației dvs. la randarea inițială.
Cu toate acestea, trebuie să vă amintiți, de asemenea, că metoda onerror()
poate fi inutil de dificilă de configurat în proiecte mai mici, cu un domeniu de eroare mai mic. Dacă sunteți sigur că aplicația dvs. nu va genera prea multe erori, metoda tradițională de aruncare/prindere va funcționa cel mai bine pentru dvs.
Reapeluri și promisiuni
Gestionarea erorilor în apeluri și promisiuni diferă din cauza designului și structurii codului. Cu toate acestea, dacă alegeți între acestea două înainte de a vă scrie codul, cel mai bine ar fi să mergeți cu promisiuni.
Acest lucru se datorează faptului că promisiunile au o construcție încorporată pentru înlănțuirea unui bloc catch()
și finally()
pentru a gestiona erorile cu ușurință. This method is easier and cleaner than defining additional arguments/reusing existing arguments to handle errors.
Keep Track of Changes With Git Repositories
Many errors often arise due to manual mistakes in the codebase. While developing or debugging your code, you might end up making unnecessary changes that may cause new errors to appear in your codebase. Automated testing is a great way to keep your code in check after every change. However, it can only tell you if something's wrong. If you don't take frequent backups of your code, you'll end up wasting time trying to fix a function or a script that was working just fine before.
This is where git plays its role. With a proper commit strategy, you can use your git history as a backup system to view your code as it evolved through the development. You can easily browse through your older commits and find out the version of the function working fine before but throwing errors after an unrelated change.
You can then restore the old code or compare the two versions to determine what went wrong. Modern web development tools like GitHub Desktop or GitKraken help you to visualize these changes side by side and figure out the mistakes quickly.
A habit that can help you make fewer errors is running code reviews whenever you make a significant change to your code. If you're working in a team, you can create a pull request and have a team member review it thoroughly. This will help you use a second pair of eyes to spot out any errors that might have slipped by you.
Best Practices for Handling Errors in JavaScript
The above-mentioned methods are adequate to help you design a robust error handling approach for your next JavaScript application. However, it would be best to keep a few things in mind while implementing them to get the best out of your error-proofing. Here are some tips to help you.
1. Use Custom Errors When Handling Operational Exceptions
We introduced custom errors early in this guide to give you an idea of how to customize the error handling to your application's unique case. It's advisable to use custom errors wherever possible instead of the generic Error
class as it provides more contextual information to the calling environment about the error.
On top of that, custom errors allow you to moderate how an error is displayed to the calling environment. This means that you can choose to hide specific details or display additional information about the error as and when you wish.
You can go so far as to format the error contents according to your needs. This gives you better control over how the error is interpreted and handled.
2. Do Not Swallow Any Exceptions
Even the most senior developers often make a rookie mistake — consuming exceptions levels deep down in their code.
You might come across situations where you have a piece of code that is optional to run. If it works, great; if it doesn't, you don't need to do anything about it.
In these cases, it's often tempting to put this code in a try block and attach an empty catch block to it. However, by doing this, you'll leave that piece of code open to causing any kind of error and getting away with it. This can become dangerous if you have a large codebase and many instances of such poor error management constructs.
The best way to handle exceptions is to determine a level on which all of them will be dealt and raise them until there. This level can be a controller (in an MVC architecture app) or a middleware (in a traditional server-oriented app).
This way, you'll get to know where you can find all the errors occurring in your app and choose how to resolve them, even if it means not doing anything about them.
3. Use a Centralized Strategy for Logs and Error Alerts
Logging an error is often an integral part of handling it. Those who fail to develop a centralized strategy for logging errors may miss out on valuable information about their app's usage.
An app's event logs can help you figure out crucial data about errors and help to debug them quickly. If you have proper alerting mechanisms set up in your app, you can know when an error occurs in your app before it reaches a large section of your user base.
It's advisable to use a pre-built logger or create one to suit your needs. You can configure this logger to handle errors based on their levels (warning, debug, info, etc.), and some loggers even go so far as to send logs to remote logging servers immediately. This way, you can watch how your application's logic performs with active users.
4. Notify Users About Errors Appropriately
Another good point to keep in mind while defining your error handling strategy is to keep the user in mind.
All errors that interfere with the normal functioning of your app must present a visible alert to the user to notify them that something went wrong so the user can try to work out a solution. If you know a quick fix for the error, such as retrying an operation or logging out and logging back in, make sure to mention it in the alert to help fix the user experience in real-time.
In the case of errors that don't cause any interference with the everyday user experience, you can consider suppressing the alert and logging the error to a remote server for resolving later.
5. Implement a Middleware (Node.js)
The Node.js environment supports middlewares to add functionalities to server applications. You can use this feature to create an error-handling middleware for your server.
The most significant benefit of using middleware is that all of your errors are handled centrally in one place. You can choose to enable/disable this setup for testing purposes easily.
Here's how you can create a basic middleware:
const logError = err => { console.log("ERROR: " + String(err)) } const errorLoggerMiddleware = (err, req, res, next) => { logError(err) next(err) } const returnErrorMiddleware = (err, req, res, next) => { res.status(err.statusCode || 500) .send(err.message) } module.exports = { logError, errorLoggerMiddleware, returnErrorMiddleware }
Apoi puteți utiliza acest middleware în aplicația dvs. astfel:
const { errorLoggerMiddleware, returnErrorMiddleware } = require('./errorMiddleware') app.use(errorLoggerMiddleware) app.use(returnErrorMiddleware)
Acum puteți defini logica personalizată în interiorul middleware-ului pentru a gestiona erorile în mod corespunzător. Nu mai trebuie să vă faceți griji cu privire la implementarea constructelor individuale de gestionare a erorilor în baza de cod.
6. Reporniți aplicația pentru a gestiona erorile programatorului (Node.js)
Când aplicațiile Node.js întâlnesc erori ale programatorului, s-ar putea să nu arunce neapărat o excepție și să încerce să închidă aplicația. Astfel de erori pot include probleme care decurg din greșelile programatorului, cum ar fi consumul mare de CPU, balonarea memoriei sau scurgerile de memorie. Cel mai bun mod de a le gestiona este să reporniți cu grație aplicația prin blocarea acesteia prin modul cluster Node.js sau un instrument unic precum PM2. Acest lucru poate asigura că aplicația nu se blochează la acțiunea utilizatorului, prezentând o experiență îngrozitoare pentru utilizator.
7. Prindeți toate excepțiile neprinse (Node.js)
Nu poți fi niciodată sigur că ai acoperit toate erorile posibile care pot apărea în aplicația ta. Prin urmare, este esențial să implementați o strategie de rezervă pentru a detecta toate excepțiile neprinse din aplicația dvs.
Iată cum poți face asta:
process.on('uncaughtException', error => { console.log("ERROR: " + String(error)) // other handling mechanisms })
De asemenea, puteți identifica dacă eroarea care a apărut este o excepție standard sau o eroare operațională personalizată. Pe baza rezultatului, puteți părăsi procesul și reporniți-l pentru a evita comportamentul neașteptat.
8. Prindeți toate respingerile de promisiuni netratate (Node.js)
La fel cum nu poți acoperi niciodată toate posibilele excepții, există șanse mari să ratezi toate posibilele respingeri de promisiuni. Cu toate acestea, spre deosebire de excepții, respingerea promisiunilor nu generează erori.
Așadar, o promisiune importantă care a fost respinsă s-ar putea să treacă ca un avertisment și să vă lase aplicația deschisă posibilității de a avea un comportament neașteptat. Prin urmare, este crucial să se implementeze un mecanism de rezervă pentru gestionarea respingerii promisiunii.
Iată cum poți face asta:
const promiseRejectionCallback = error => { console.log("PROMISE REJECTED: " + String(error)) } process.on('unhandledRejection', callback)
rezumat
Ca orice alt limbaj de programare, erorile sunt destul de frecvente și naturale în JavaScript. În unele cazuri, este posibil să fie nevoie chiar să aruncați erori în mod intenționat pentru a indica răspunsul corect utilizatorilor dvs. Prin urmare, înțelegerea anatomiei și a tipurilor lor este foarte importantă.
Mai mult, trebuie să fii echipat cu instrumentele și tehnicile potrivite pentru a identifica și a preveni erorile de la eliminarea aplicației.
În cele mai multe cazuri, o strategie solidă pentru a gestiona erorile cu o execuție atentă este suficientă pentru toate tipurile de aplicații JavaScript.
Există și alte erori JavaScript pe care încă nu le-ați putut rezolva? Orice tehnici pentru gestionarea constructivă a erorilor JS? Spune-ne în comentariile de mai jos!