Umění házet chyby JavaScriptu, část 2

Ve svém posledním příspěvku jsem mluvil o tom, jak a kdy házet chyby JavaScriptu. Dostal jsem spoustu odpovědí a doplňujících otázek, tak jsem si řekl, že budu v diskusi pokračovat a vysvětlím trochu víc o tom, jak házet vlastní chyby. Základní syntaxe je:

throw new Error("message");

Funguje to ve všech prohlížečích a zobrazí informace o chybě stejným způsobem, jako by to byla jakákoli neúmyslná chyba JavaScriptu. Řetězec „zpráva“ je uložen v message vlastnost objektu (což je to, co prohlížeč používá k zobrazení zprávy). Pravidelně se setkávám s tím, že lidé házejí chyby pouhým zadáním řetězce, jako je tento:

throw "message";

Pokud tak učiníte, dojde k chybě, ale ne všechny prohlížeče reagují tak, jak byste očekávali. Firefox, Opera a Chrome každý zobrazí zprávu „nezachycená výjimka“ a poté zahrne řetězec zprávy. Safari a Internet Explorer jednoduše vyhodí chybu „nezachycená výjimka“ a vůbec neposkytnou řetězec zprávy. Je zřejmé, že to není optimální z hlediska ladění.

Samozřejmě můžete hodit jakýkoli typ dat, který chcete. Neexistují žádná pravidla zakazující konkrétní datové typy:

throw { name: "Nicholas" };
throw true;
throw 12345;
throw new Date();

Jediná věc, kterou si pamatujte, je, že vyvolání jakékoli hodnoty bude mít za následek chybu, pokud nebude zachycena pomocí try-catch tvrzení. Firefox, Opera a Chrome volají String() na hodnotě, která byla vyvolána, aby se zobrazilo něco logického jako chybová zpráva; Safari a Internet Explorer ne. Jediným spolehlivým způsobem, jak nechat všechny prohlížeče zobrazit vaši vlastní chybovou zprávu, je použít Error objekt.

ECMA-262, 3rd Edition ve skutečnosti specifikuje sedm typů chybových objektů. Ty jsou využívány jádrem JavaScriptu, když nastanou různé chybové stavy, a lze je také vytvořit ručně:

  • Error – základní typ pro všechny chyby. Ve skutečnosti nikdy neházel motorem.
  • EvalError – vyvoláno, když dojde k chybě během provádění kódu přes eval()
  • RangeError – vrženo, když je číslo mimo hranice svého rozsahu. Například při pokusu o vytvoření pole s -20 položkami (new Array(-20) ). Při běžném provádění k nim dochází zřídka.
  • ReferenceError – vyvoláno, když je objekt očekáván, ale není dostupný, například při pokusu o volání metody na null odkaz.
  • SyntaxError – vyvoláno při předání kódu do eval() má chybu syntaxe.
  • TypeError – vyvolán, když je proměnná neočekávaného typu. Například new 10 nebo "prop" in true .
  • URIError – vyvoláno, když je do encodeURI předán nesprávně formátovaný řetězec URI , encodeURIComponent , decodeURI nebo decodeURIComponent .

Pochopení, že existují různé typy chyb, může usnadnit jejich řešení. Všechny typy chyb dědí z Error takže zkontrolujte typ pomocí instanceof Error vám neposkytne žádné užitečné informace. Kontrolou specifičtějších typů chyb získáte robustnější zpracování chyb:

try {
    //something that causes an error
} catch (ex){
    if (ex instanceof TypeError){
        //handle the error
    } else if (ex instanceof ReferenceError){
        //handle the error
    } else {
        //handle all others
    }
}

Pokud házíte vlastní chyby a házíte datový typ, který není chybou, můžete snadněji rozlišit mezi svými vlastními chybami a chybami, které hází prohlížeč. Vyhození skutečného Error má však několik výhod objekty namísto jiných typů objektů.

Za prvé, jak již bylo zmíněno dříve, chybová zpráva se zobrazí v běžném mechanismu zpracování chyb prohlížeče. Za druhé, prohlížeč připojí další informace k Error předměty, když jsou vrženy. Ty se liší prohlížeč od prohlížeče, ale poskytují kontextové informace o chybě, jako je číslo řádku a číslo sloupce a v některých prohlížečích informace o zásobníku a zdroji. Samozřejmě ztratíte možnost rozlišovat mezi svými vlastními chybami a chybami vyvolanými prohlížečem, pokud použijete pouze Error konstruktor.

Řešením je vytvořit si vlastní typ chyby, který dědí z Error . Například:

function MyError(message){
    this.message = message;
}

MyError.prototype = new Error();

Tento kód má dvě důležité části:1) message vlastnost, která je nezbytná k tomu, aby prohlížeče znaly skutečný chybový řetězec a 2) nastavení prototypu na instanci Error , která identifikuje objekt jako chybu enginu JavaScript. Nyní můžete vyvolat instanci MyError a nechte prohlížeč reagovat, jako by se jednalo o nativní chybu:

throw new MyError("Hello world!");

Jedinou výhradou k tomuto přístupu je, že Internet Explorer starší než verze 8 nezobrazí chybovou zprávu. Místo toho se zobrazí obecná chybová zpráva „vyhozena výjimka, ale nebyla zachycena“. Vyhození vlastních chybových objektů vám umožňuje testovat konkrétně na vaše vlastní chyby:

try {
    //something that causes an error
} catch (ex){
    if (ex instanceof MyError){
        //handle my own errors
    } else {
        //handle all others
    }
}

Pokud vždy zachytíte nějaké chyby, které vyvoláte, pak by na malé hlouposti IE nemělo tolik záležet. Výhody takového přístupu jsou v systému se správným zpracováním chyb obrovské. Tento přístup vám poskytuje mnohem větší flexibilitu a informace pro určení správného postupu pro danou chybu.