4. blokk · Node felé · 13. fejezet
Egy szerver naponta ezerszer kap rossz adatot: hiányzó mezőt, hibás JSON-t, nem létező termékazonosítót. Ha ilyenkor
a program leáll, mindenki más kérése is elveszik. Ebben a fejezetben megtanulod olvasni a hibaüzenetet és a
stack trace-t, elkapni a hibát try / catch-csel, dobni a sajátodat
throw-val, és extends Error-ral saját hibaosztályt írni —
ez az Express hibakezelő middleware-jének az alapja.
null-t.catch-ben instanceof-fal válogatsz.| Fajta | Mikor derül ki | Példa | Mit tehetsz |
|---|---|---|---|
| Szintaktikai | a kód le sem fut — a Node már beolvasáskor megáll | hiányzó zárójel, cosnt, lezáratlan szöveg | elolvasod a hibaüzenetet (sor:oszlop), javítod |
| Futásidejű | futás közben, egy adott utasításnál | null.nev, nem létező változó, hibás JSON | ezt lehet elkapni (try / catch) — ez a fejezet témája |
| Logikai | soha nem „szól" — csak rossz az eredmény | < helyett <=, rossz sorrendű else if | console.log-os nyomkövetés, tesztek (mint az ellenőrző itt) |
Amikor futásidejű hiba történik, a JavaScript kivételt dob (throw): az aktuális függvény azonnal megszakad, a hiba „felfelé" halad a hívó függvényekhez, és ha senki nem kapja el, a program leáll, Node-ban a terminálba írt hibaüzenettel. A hibakezelés arról szól, hogy te döntsd el, hol és hogyan áll meg ez a folyamat.
Minden dobott hiba egy objektum, általában az Error osztály (vagy egy leszármazottja) példánya —
a 12. fejezet osztályai itt jönnek jól. A hiba neve már sokat elárul arról, mit rontottunk el:
| Osztály | Mit jelent | Tipikus üzenet |
|---|---|---|
SyntaxError | a kód vagy egy feldolgozott szöveg nem érvényes | Unexpected token '}' in JSON at position 12 |
ReferenceError | nem létező változóra hivatkozol (elgépelés, hatókör) | termkek is not defined |
TypeError | rossz típusú értéken végzel műveletet — a leggyakoribb | Cannot read properties of null (reading 'nev')termek.brutto is not a function |
RangeError | egy érték a megengedett tartományon kívül esik | Invalid array length, toFixed() digits argument must be between 0 and 100 |
Error | az általános ős — a saját hibáidat ebből dobod | amit te írsz: Nincs elég készlet: Egér |
const termek = null; console.log(termek.nev); // TypeError: Cannot read properties of null (reading 'nev') console.log(termkek); // ReferenceError: termkek is not defined JSON.parse("{rossz"); // SyntaxError: Expected property name or '}' in JSON at position 1
„Cannot read properties of null (reading 'nev')" = valami, amiről azt hitted, objektum, valójában
null, és annak a .nev-ét kérted. A kérdés tehát nem a nev,
hanem: miért null az a valami? — általában egy find, ami nem talált, vagy egy hiányzó mező.
Ha Node-ban egy hibát senki nem kap el, a terminálban ilyet látsz. Ne ijedj meg a mennyiségétől — három részből áll, és a felső kettő a fontos:
$ node index.js
/home/anna/webshop/keszlet.js:4
throw new Error(`Nincs elég készlet: ${nev}`);
^
Error: Nincs elég készlet: Egér
at kivesz (/home/anna/webshop/keszlet.js:4:11)
at rendel (/home/anna/webshop/rendeles.js:9:3)
at file:///home/anna/webshop/index.js:6:1
at ModuleJob.run (node:internal/modules/esm/module_job:271:25)
Node.js v22.12.0
keszlet.js:4), a ^ az oszlopot.Error: Nincs elég készlet: Egér — a hiba neve és üzenete. Ezt keresd először.at fuggveny (fájl:sor:oszlop) sorok fentről lefelé a hiba helyétől
a program indulásáig: a kivesz-t a rendel hívta, azt az index.js 6. sora.
A node:internal sorok a Node saját belseje — ezeket átugorhatod.A módszer: keresd meg a legfelső olyan sort, amely a te fájlodra mutat — ott történt a baj. A lánc többi sora azt mondja el, hogyan jutott oda a program, ami akkor kell, ha a hiba helye rendben van, csak rossz adattal hívták.
A try blokkba kerül a „kockázatos" kód. Ha benne hiba dobódik, a futás azonnal a
catch blokkba ugrik (a try hátralévő sorai kimaradnak), és a program utána
tovább fut:
try { const termek = null; console.log(termek.nev); // itt dobódik a TypeError console.log("ez már nem fut le"); } catch (e) { console.log("Elkaptuk:", e.message); // Elkaptuk: Cannot read properties of null (reading 'nev') } console.log("A program tovább fut!");
A catch (e) zárójelében kapod meg a hibaobjektumot (gyakori név: e, err,
error). Ha nincs rá szükséged, a modern JS-ben el is hagyhatod: catch { … }.
A finally blokk minden esetben lefut: ha nem volt hiba, ha volt és elkaptuk, sőt akkor is,
ha a try-ban return áll. Takarításra való: fájl vagy kapcsolat lezárása, „töltés" jelző kikapcsolása.
function feldolgoz(adat) { console.log("kapcsolat nyitása"); try { if (!adat) throw new Error("Nincs adat"); return "kész"; } catch (e) { console.log("hiba:", e.message); return "sikertelen"; } finally { console.log("kapcsolat zárása"); // a return után is lefut } } console.log(feldolgoz(null)); // kapcsolat nyitása → hiba: Nincs adat → kapcsolat zárása → sikertelen
Az üres catch (e) {} a legrosszabb: a hiba eltűnik, a program „megy tovább" rossz adattal, és napokkal később
derül ki, hogy valami nem stimmel. A catch-ben mindig csinálj valamit: írd ki
(console.error), adj vissza értelmes alapértéket, vagy dobd tovább (throw e).
És csak azt tedd try-ba, ami tényleg hibázhat — ne az egész programot.
A catch-ben kapott objektumnak három fontos tulajdonsága van:
| Tulajdonság | Mit ad | Példa |
|---|---|---|
e.name | a hiba fajtája (az osztály neve) | "TypeError", "Error", "ValidationError" |
e.message | az üzenet — amit a new Error("…")-nak adtál | "Nincs elég készlet: Egér" |
e.stack | a teljes stack trace szövegként (név + üzenet + at sorok) | többsoros string |
function harmadik() { throw new Error("Valami elromlott"); } function masodik() { harmadik(); } function elso() { masodik(); } try { elso(); } catch (e) { console.log(e.name); // Error console.log(e.message); // Valami elromlott console.log(e.stack.split("\n")[0]); // Error: Valami elromlott console.error("HIBA:", e.message); // a hibacsatornára ír }
A console.error ugyanúgy néz ki, mint a console.log, de Node-ban a hibakimenetre
(stderr) ír, nem a normál kimenetre. Ezért a naplózó és a futtató környezet szét tudja válogatni: a rendes kiírás mehet egy fájlba,
a hibák egy másikba vagy riasztásba. Hibát tehát console.error-ral írj ki, ne log-gal.
Ha az egész objektumot adod át neki (console.error(e)), Node a stack trace-t is kiírja.
Nemcsak a JavaScript dobhat hibát: te is, ha egy függvény olyan adatot kap, amivel nem tud értelmesen dolgozni.
A throw new Error("üzenet") azonnal megszakítja a függvényt, és a hiba a hívóhoz kerül:
function oszt(a, b) { if (b === 0) { throw new Error("Nullával nem osztunk!"); // innen nem fut tovább } return a / b; } try { console.log(oszt(10, 0)); } catch (e) { console.log(e.message); // Nullával nem osztunk! }
Az üzenetbe tedd bele a konkrét értéket, amivel baj van — template literállal:
throw new RangeError(`Index kívül esik: ${i}`). Bármelyik beépített osztályt dobhatod
(RangeError, TypeError), ha az jobban leírja a bajt; a legtöbbször a sima Error elég.
A rossz eseteket a függvény elején, külön-külön if-ekkel szűrd ki, és dobj vagy térj vissza azonnal.
Így a „boldog út" nem kerül egyre mélyebb else ágakba, és minden ellenőrzés egy sor:
function kivesz(egyenleg, osszeg) { if (osszeg <= 0) throw new Error("Érvénytelen összeg"); // őr 1 if (osszeg > egyenleg) throw new Error("Nincs elég fedezet"); // őr 2 return egyenleg - osszeg; // innentől biztos, hogy jók az adatok }
| Helyzet | Válasz | Példa |
|---|---|---|
| A hiányzó eredmény normális, várható kimenet | null / undefined / üres tömb | keresés, ami nem talál: find → undefined; üres verem pop() → null |
| Egy művelet sikerült vagy nem, és a hívó úgyis elágazik rá | true / false | kosar.torol("Egér"), szamla.kivesz(500) fedezet nélkül |
| A bemenet érvénytelen, a függvény nem tud értelmesen folytatni | throw | nullával osztás, negatív ár, ismeretlen kuponkód, hibás JSON |
| Rossz elemek egy listában, a többi feldolgozható | kihagyás, nem hiba | a nem szám elemek átugrása összegzéskor |
Ökölszabály: ha a hívó valószínűleg elfelejtené ellenőrizni a visszaadott null-t, és ebből
később TypeError lenne, inkább dobj — egy hangos hiba jobb, mint egy csendes rossz adat.
Ha a hívónak különbséget kell tennie a hibák között („ez a felhasználó hibája, az meg a mienk"), az üzenet szövegét
vizsgálgatni törékeny. Ehelyett az Error-ból örökölsz egy saját osztályt — pont úgy, mint a 12. fejezetben:
class ValidationError extends Error { constructor(uzenet, mezo) { super(uzenet); // az Error kapja az üzenetet → e.message this.name = "ValidationError"; // különben "Error" maradna a neve this.mezo = mezo; // saját plusz adat } } function ellenorizTermek(termek) { if (!termek.nev) throw new ValidationError("A név kötelező", "nev"); if (termek.ar < 0) throw new ValidationError("Az ár nem lehet negatív", "ar"); return true; }
A catch minden hibát elkap — a tiédet és a véletlen TypeError-t is. Ezért
instanceof-fal válogass: a sajátodat kezeled, a többit tovább dobod, hogy ne tűnjön el:
try { ellenorizTermek({ nev: "Egér", ar: -5 }); } catch (e) { if (e instanceof ValidationError) { console.log(`Érvénytelen mező: ${e.mezo} – ${e.message}`); // Érvénytelen mező: ar – Az ár nem lehet negatív } else { throw e; // nem a miénk → menjen tovább felfelé } }
Egy másik gyakori minta: a catch nem dob, hanem eredményobjektumot ad vissza —
{ ok: true } vagy { ok: false, mezo: e.mezo, hiba: e.message } — így a hívó
egyszerű if-fel dolgozza fel a kimenetet. Az űrlap-validálás pontosan így működik.
Az Express 5-ben a route-okban dobott hibák egy központi hibakezelő middleware-be futnak, amelynek négy paramétere van:
(err, req, res, next). Ott egyetlen helyen döntöd el a választ a hiba típusa alapján:
err instanceof NotFoundError → 404, ValidationError → 400 az err.mezo-val,
minden más → 500 és console.error(err). Sok projekt ezért a hibaosztályba tesz egy status
mezőt (this.status = 404), és a middleware csak res.status(err.status ?? 500)-t ír.
Ugyanezt az extends Error + name + saját mező mintát írod meg itt a feladatokban.
A 11. fejezetből tudod: a JSON.parse hibás szövegre SyntaxError-t dob. Kívülről (fájl, hálózat,
felhasználó) érkező szöveg bármikor lehet hibás, ezért a parse-olás a klasszikus try / catch-eset:
function biztonsagosParse(szoveg) { try { return JSON.parse(szoveg); } catch { return null; // hibás szöveg → null, a program nem omlik össze } } console.log(biztonsagosParse('{"nev":"Egér"}')); // { nev: 'Egér' } console.log(biztonsagosParse("{rossz")); // null
Gyakran nem null-t akarsz, hanem a beépített, technikai üzenet helyett egy sajátot — és utána
még ellenőrzöd is, hogy a kapott adat a várt alakú-e. Ilyenkor a try-ban csak a parse legyen,
a további ellenőrzés a try után — különben a saját hibádat is elkapná ugyanaz a catch:
function jsonOsszeg(szoveg) { let adat; try { adat = JSON.parse(szoveg); } catch { throw new Error("Hibás JSON"); // saját üzenet a SyntaxError helyett } if (!Array.isArray(adat)) throw new Error("Nem tömb"); // a try-on kívül return adat.reduce((s, x) => s + x, 0); }
Elkapod egy alacsony szintű réteg hibáját (JSON, fájl, adatbázis), és a saját szintednek megfelelő hibát dobsz helyette
(Hibás JSON, NotFoundError). A hívónak így nem kell ismernie a belső részleteket —
Node-ban ez a service-réteg egyik fő dolga.
Dobj és kapj el hibákat, nézd meg a beépített hibafajták üzeneteit, próbáld ki a finally-t és a saját hibaosztályt.
Egy el nem kapott hiba itt is úgy jelenik meg, ahogy Node-ban a terminálban: a hiba nevével és üzenetével.
Válassz mintát vagy írj sajátot — majd Futtatás (Ctrl+Enter) ↓
Függvényeket írsz, amelyeket az ellenőrző különböző argumentumokkal hív. Újdonság: egyes teszteknél a függvénynek hibát kell dobnia —
ezeknél a „VÁRT" oszlopban ez áll: „hibát dob ezzel az üzenettel: …", és a teszt csak akkor zöld, ha a dobott hiba
message-e karakterre pontosan egyezik (ékezet, írásjel, idézőjel is számít). Ha a függvényed
ilyenkor nem dob, hanem visszaad valamit, a „KAPOTT" sor megmutatja, mit. Más feladatoknál épp fordítva: a függvény
soha nem dobhat, hanem null-t vagy eredményobjektumot ad vissza.
⭐ alap · ⭐⭐ haladó · ⭐⭐⭐ kihívás — a haladásod ebben a böngészőben megmarad.
Másold az üzenetet a feladat szövegéből, ne gépeld. Template literálnál figyelj a változó helyére és a körülötte lévő
idézőjelekre (`Nem szám: "${szoveg}"`). És a throw előtt ne legyen
return — a dobás után már semmi sem fut le a függvényben.
TypeError (rossz típus, null.nev), ReferenceError (nincs ilyen változó), SyntaxError (hibás kód/JSON), RangeError (tartományon kívül); ős: Error.at fuggveny (fájl:sor:oszlop) sorok a hívási lánc a hiba helyétől lefelé — a legfelső saját fájlod a gyanús.try { … } catch (e) { … } finally { … }: hibánál a catch fut, a finally mindig (return után is). Üres catch tilos.e.name, e.message, e.stack; hibát console.error-ral írj ki (stderr).throw new Error("üzenet") megszakítja a függvényt; guard clause-okkal a függvény elején. Dobj, ha a bemenet érvénytelen; null/false, ha a „nincs" normális kimenet.class ValidationError extends Error + super(uzenet) + this.name + saját mező; a catch-ben instanceof, a többit throw e.JSON.parse mindig try-ban; csak a parse legyen benne, az ellenőrzés utána — és fordítsd le a hibát a saját szintedre.Az utolsó fejezetben a kódot fájlokra bontod: export / import, a Node
modulrendszere, egy mini webshop-projekt fájlszerkezete — majd egy záró feladatsor az egész kurzus anyagából,
hibakezeléssel, osztályokkal és tömb-metódusokkal együtt.