JavaScript - Error Handling


Rukovanje greškama (Error Handling)

Ponekad vaš JavaScript kod ne radi tako glatko kako ste očekivalo, što rezultuje greškom. Postoji nekoliko razloga koji mogu uzrokovati greške, na primjer:

  • Problem s mrežnom vezom
  • Korisnik je možda unio neispravnu vrijednost u polje obrasca
  • Navođenje objekata ili funkcija koje ne postoje
  • Netačni podaci koji se šalju ili primaju od web servera
  • Usluga kojoj aplikacija treba pristupiti možda je privremeno nedostupna

Ove vrste grešaka poznate su kao runtime greške, jer se javljaju u trenutku kada se skripta izvodi. Profesionalna aplikacija mora imati mogućnosti da graciozno riješi takve greške pri izvođenju. To obično znači informisanje korisnika o problemu jasnije i preciznije.



Izjava try...catch

JavaScript pruža naredbu try-catch za hvatanje grešaka u izvršavanju i graciozno rukovanje njima. Bilo koji kod koji bi mogao izazvati grešku trebao bi biti smješten u bloka try izraza, a kod koji obrađuje grešku smješten je u blok catch, kao što je prikazano u primjeru:

try {
    // Kod koji može izazvati grešku
} catch(error) {
    // Akcija koju treba izvršiti kada se dogodi greška
}

Ako se u bilo kojem trenutku bloka try dogodi greška, izvršavanje koda odmah se prenosi iz bloka try u blok catch. Ako se u bloku try ne dogodi greška, blok catch će se zanemariti, a program će se nastaviti izvršavati nakon naredbe try-catch. Sljedeći primjer pokazuje kako izjava try-catch zapravo radi:

try {
    var greet = "Ćao, svima!";
    document.write(greet);
    
    // Pokušaj pristupa nepostojećoj varijabli
    document.write(welcome);
    
    // Ako se dogodi greška, sljedeći se red neće izvršiti
    alert("Sve se izjave uspješno izvršavaju.");
} catch(error) {
    // Obrada greške
  alert("Uhvaćena greška: " + error.message);
}
 
// Nastavite izvršenje
document.write("<p>Volim da učim JS uz IT TUTORIJALE!</p>");
Pogledajmo kako koristiti primjer u praksi:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JavaScript try-catch izjave</title>
</head>
<body>
    <script>
    try {
        var greet = "Ćao, svima!";
        document.write(greet);
        
        // Pokušaj pristupa nepostojećoj varijabli
        document.write(welcome);
        
        // Ako se dogodi greška, sljedeći se red neće izvršiti
        alert("Sve se izjave uspješno izvršavaju.");
    } catch(error) {
        // Obrada greške
      alert("Uhvaćena greška: " + error.message);
    }
     
    // Nastavite izvršenje
    document.write("<p>Volim da učim JS uz IT TUTORIJALE!</p>");
    </script>
</body>
</html>

Gornja skripta generisaće grešku koja se prikazuje u dijaloškom okviru za upozorenje, umjesto da je ispisuje na konzolu pretraživača. Osim toga, program se nije naglo zaustavio iako je došlo do greške. Takođe imajte na umu da ključnu riječ catch slijedi identifikator u zagradama. Ovaj se identifikator ponaša kao parametar funkcije. Kada se dogodi greška, JavaScript tumač generiše objekt koji sadrži detalje o njemu. Ovaj objekt greške se zatim prosljeđuje kao argument za catch rukovanje.



try...catch...finally izjava

Izjava try-catch može imati i klauzulu finally. Kod unutar bloka finally će se uvijek izvršiti, bez obzira da li je došlo do greške u bloku try ili ne. Sljedeći primjer će uvijek prikazati ukupno vrijeme potrebno za dovršenje izvršenja koda.

// Dodjeljivanje vrijednosti koja se vraća dijaloškim okvirom za upit varijabli
var num = prompt("Unesite pozitivan cijeli broj između 0 i 100");

// Pohranjivanje vremena kada započinje izvršenje
var start = Date.now();

try {
    if(num > 0 && num <= 100) {
        alert(Math.pow(num, num)); // baza eksponencijalne snage
    } else {
        throw new Error("Unesena je neispravna vrijednost!");
    }
} catch(e) {
    alert(e.message);
} finally {
    // Prikaz vremena potrebnog za izvršavanje koda
    alert("Izvršenje je trajalo: " + (Date.now() - start) + "ms");
}
Pogledajmo kako koristiti primjer u praksi:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JavaScript try-catch-finally izjave</title>
</head>
<body>
    <script>
    // Dodjeljivanje vrijednosti koja se vraća dijaloškim okvirom za upit varijabli
    var num = prompt("Unesite pozitivan cijeli broj između 0 i 100");
    
    // Pohranjivanje vremena kada započinje izvršenje
    var start = Date.now();
    
    try {
        if(num > 0 && num <= 100) {
            alert(Math.pow(num, num)); // baza eksponencijalne snage
        } else {
            throw new Error("Unesena je neispravna vrijednost!");
        }
    } catch(e) {
        alert(e.message);
    } finally {
        // Prikaz vremena potrebnog za izvršavanje koda
        alert("Izvršenje je trajalo: " + (Date.now() - start) + "ms");
    }
    </script>
    <p><strong>Napomena: </strong><code> Math.pow (baza, 
    eksponent) </code> metoda vraća broj koji predstavlja datu bazu 
    preuzetu u moć datog eksponenta, tj. <code>base<sup > 
    eksponent</sup></code>.</p>
</body>
</html>


Bacanje grešaka (Throwing Errors)

Do sada smo vidjeli greške koje automatski raščlanjuje JavaScript kada se dogodi greška. Međutim, moguće je i grešku baciti ručno pomoću naredbe bacanja (throw statement). Opšti oblik (ili sintaksa) izjave throw je: throw expression;. Izraz može biti objekt ili vrijednost bilo kojeg tipa podataka. Međutim, bolje je koristiti objekte, po mogućnosti s imenima i svojstvima poruke. Ugrađeni JavaScript konstruktor Error() pruža prikladan način za stvaranje objekta greške. Pogledajmo nekoliko primjera:

throw 123;
throw "Nedostaju vrijednosti!";
throw true;
throw { name: "InvalidParameter", message: "Parametar nije broj!" };
throw new Error("Nešto nije dobro!");
Pogledajmo kako koristiti primjer u praksi:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JavaScript throw izjava</title>
</head>
<body>
    <script>
    var num = prompt("Unesite cijelu vrijednost");
    
    try {
        if(num == "" || num == null || !Number.isInteger(+num)) {
            throw new Error("Nevažeća vrijednost!");
        } else {
            document.write("Tačna vrijednost!");
        }
    } catch(e) {
        document.write(e.message);
    }
    </script>
</body>
</html>

Sada ćemo stvoriti funkciju squareRoot() za pronalaženje kvadratnog korijena broja. To se može učiniti jednostavno upotrebom JavaScript ugrađene funkcije Math.sqrt(), ali problem je u tome što vraća NaN za negativne brojeve, bez davanja nagovještaja o tome što je pošlo po zlu. Riješićemo ovaj problem izbacivanjem prilagođene greške ako je naveden negativan broj.

function squareRoot(number) {
    // Throw error ako je broj negativan
    if(number < 0) {
        throw new Error("Žao nam je, ne mogže se izračunati kvadratni korijen negativnog broja.");
    } else {
        return Math.sqrt(number);
    }
}
    
try {
    squareRoot(16);
    squareRoot(625);
    squareRoot(-9);
    squareRoot(100);
    
    // Ako se izbaci greška, sljedeći red se neće izvršiti
    alert("Svi proračuni se izvode uspješno.");
} catch(e) {
    // Obrada greške
    alert(e.message);
}
Pogledajmo kako koristiti primjer u praksi:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Throwing Error u JavaScript</title>
</head>
<body>
    <script>
    function squareRoot(number) {
        // Throw error ako je broj negativan
        if(number < 0) {
            throw new Error("Žao nam je, ne mogže se izračunati kvadratni korijen negativnog broja.");
        } else {
            return Math.sqrt(number);
        }
    }
        
    try {
        squareRoot(16);
        squareRoot(625);
        squareRoot(-9);
        squareRoot(100);
        
        // Ako se izbaci greška, sljedeći red se neće izvršiti
        alert("Svi proračuni se izvode uspješno.");
    } catch(e) {
        // Obrada greške
        alert(e.message);
    }
    </script>
</body>
</html>


Vrste grešaka (Error Types)

Objekt Error je osnovni tip svih grešaka i ima dva glavna svojstva - svojstvo imena koje specifikuje vrstu greške i svojstvo poruke koje sadrži poruku koja detaljnije opisuje grešku. Svaka bačena greška biće instanca objekta Error. Postoji nekoliko različitih vrsta grešaka koje se mogu pojaviti tokom izvršavanja JavaScript programa, poput: RangeError, ReferenceError, SyntaxError, TypeError i URIError. Sljedeći dio detaljnije opisuje svaku od ovih vrsta grešaka:



RangeError

RangeError se baca kada koristite broj koji je izvan raspona dopuštenih vrijednosti. Na primjer, stvaranje niza negativne dužine baciće RangeError.

var num = 12.735;
num.toFixed(200); // baca grešku dometa (dopušteni raspon od 0 do 100)

var array = new Array(-1); // baca grešku dometa
Pogledajmo kako koristiti primjer u praksi:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JavaScript RangeError</title>
</head>
<body>
    <script>
    var num = 12.735;
    
    try {        
        num.toFixed(200); // baca grešku dometa (dopušteni raspon od 0 do 100)
    } catch(e) {
        document.write(e.name + ": " +  e.message);
    }
    </script>
</body>
</html>


ReferenceError

ReferenceError se obično baca kada pokušate uputiti ili pristupiti varijabli ili objektu koji ne postoji. Sljedeći primjer pokazuje kako se javlja ReferenceError.

var firstName = "Miloš";
console.log(firstname); // baca referentnu grešku (imena varijabli razlikuju velika i mala slova)

undefinedObj.getValues(); //baca referentnu grešku

nonexistentArray.length; // baca referentnu grešku
Pogledajmo kako koristiti primjer u praksi:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JavaScript ReferenceError</title>
</head>
<body>
    <script>
    var firstName = "Miloš";
    
    try {        
        document.write(firstname); // baca referentnu grešku (imena varijabli razlikuju velika i mala slova)
    } catch(e) {
        document.write(e.name + ": " +  e.message);
    }
    </script>
</body>
</html>


SyntaxError

SyntaxError se baca za vrijeme izvođenja ako postoji bilo kakav problem sa sintaksom u vašem JavaScript kodu. Na primjer, ako zatvaračka zagrada nedostaje, petlje nisu pravilno strukturisane, i tako dalje.

var array = ["a", "b", "c"];
document.write(array.slice(2); // baca sintaksnu grešku (nedostaje zagrada)

alert("IT TUTORIJALI!'); // baca sintaksnu grešku (neusklađenost citata)
Pogledajmo kako koristiti primjer u praksi:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JavaScript SyntaxError</title>
</head>
<body>
    <script>
    try {        
        eval("alert('IT TUTORIJALI!)"); // baca sintaksnu grešku (nedostaje zagrada)
    } catch(e) {
        document.write(e.name + ": " +  e.message);
    }
    </script>
</body>
</html>


TypeError

Greška tipa Type baca se kada vrijednost nije očekivani tip. Na primjer, pozivanje metode stringa na broju, pozivanje metode niza na string itd.

var num = 123;
num.toLowerCase(); /* baca grešku u tipu (pošto je toLowerCase() 
metoda stringa, broj se ne može pretvoriti u mala slova) */

var greet = "IT TUTORIJALI!"
greet.join() // baca grešku u tipu (jer je join() metoda niza) 
Pogledajmo kako koristiti primjer u praksi:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JavaScript TypeError</title>
</head>
<body>
    <script>
    var num = 123;

    try {        
        num.toLowerCase(); /*baca grešku u tipu (pošto je 
        toLowerCase() metoda stringa, broj se ne može pretvoriti u mala slova)*/             
    } catch(e) {
        document.write(e.name + ": " +  e.message);
    }
    </script>
</body>
</html>


URIError

URIError se baca kada ste naveli nevažeći URI (znači Uniform Resource Identifier) na funkcije povezane s URI, poput encodeURI() ili decodeURI(), kao što je ovdje prikazano:

var a = "%E6%A2%B";
decodeURI(a);  // baca URI error

var b = "\uD800";
encodeURI(b);   // baca URI error
Pogledajmo kako koristiti primjer u praksi:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JavaScript URIError</title>
</head>
<body>
    <script>
    var a = "%E6%A2%B";

    try {        
        decodeURI(a);  // baci URI error          
    } catch(e) {
        document.write(e.name + ": " +  e.message);
    }
    </script>
</body>
</html>

Određeni tip greške takođe se može baciti ručno pomoću njihovog odgovarajućeg konstruktora i naredbe throw, npr. za bacanje TypeError možete koristiti konstruktor TypeError(), pogledajmo primjer:

var num = prompt("Please enter a number");

try {
    if(num != "" && num !== null && isFinite(+num)) {
        alert(Math.exp(num));
    } else {
        throw new TypeError("Niste unijeli broj.");
    }
} catch(e) {
    alert(e.name);
    alert(e.message);
    alert(e.stack); // nestandardno svojstvo
}
Pogledajmo kako koristiti primjer u praksi:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JavaScript Bacanje određene vrste greške</title>
</head>
<body>
    <script>
    var num = prompt("Unesite broj");

    try {
        if(num != "" && num !== null && isFinite(+num)) {
            document.write(Math.exp(num));
        } else {
            throw new TypeError("Niste unijeli broj.");
        }
    } catch(e) {
        document.write(e.name + ": " + e.message);
    }
    </script>
    <p><strong>Napomena: </strong><code> Math.exp(x) </code>
        metoda vraća broj koji predstavlja <code> e <sup> x </sup>
        </code>, gdje je <code> e </code> Eulerov broj i
        <code> x </code> je argument.</p>
    </body>
</html>