Přejít k navigační liště

Zdroják » Různé » Došlo k chybě ve skriptu

Došlo k chybě ve skriptu

Články Různé

Omlouváme se, ale článek, který na serveru hledáte, tu pravděpodobně není. Možná ho někdo smazal, možná tu nikdy nebyl, možná jste se uklepli v adrese. Server možná ztratil spojení s databází. Máte nepodporovaný prohlížeč. Došlo k obecné chybě. Omlouváme se. Zkuste to za chvíli znovu… Co s tím uděláme?

Ohlásit chybu uživateli je složité.

Myslíte, že není? Že není nic snazšího než napsat „Chyba: dělení nulou na adrese 0×00053AFD“? Ale to je něco jiného. To není hlášení chyby, to je diagnóza. Dokonce i napsat „Ouha, něco se pokazilo, zkuste to za chvíli“ je lepší než tohle. Chybové hlášení, které uživatele zmate, je mnohem horší než takové, které mu neřekne nic.

K tomu, aby chybové hlášení fungovalo, je zapotřebí dvou věcí.

Za prvé: přiznat si, že mohu udělat chybu. Udělat chybu není životní prohra, nemusíte se proto tvářit, že jste ji neudělali a snažit se ji zamaskovat. Vývojářské pravidlo říká „zhavarujte rychle!“ Pokud je evidentní, že jste něco pokazili, neošetřili, zmotali, nešlapte v tom a raději to rychle opravte. Uživatelům se omluvíte, oni to pochopí a nikdo vás nebude topit na lžíci vody, protože (snad kromě některých komentátorů) děláme chyby všichni. Přiznat chybu, napravit ji, omluvit se.


motifake.com

Udělali jste chybu… Víte, co to znamená…

Za druhé: Musím se o chybě dozvědět a mít způsob, jak ji zpracovat.

Jak hlásit chyby?

Důležitý moment je vědět, že uživatel a vývojář potřebují v případě chyby zcela rozdílné informace. Vývojář potřebuje záznamy, výpisy, místo havárie… Uživatel to vědět nepotřebuje, ale potřebuje být ujištěn, že se opravdu stalo něco špatně, a co má dělat.

Pokud chyba vznikla v důsledku nějaké uživatelovy činnosti, jako že udělal něco, co udělat neměl, zmáčkl něco, co zmáčknout neměl, napsal něco špatně a tak, je na místě být v chybovém hlášení jasný a přesný: „Zadal jste špatně číslo, zadejte ho takto…“, „Musíte zaškrtnout jednu z možností“, „Na toto tlačítko, prosím, už nikdy neklikejte, pokud chcete, aby váš kocour přežil“ a podobně. Uživatelovy chyby se dají většinou dobře identifikovat a zachytit. Ale co chyby systému, nebo dokonce chyby v kódu? (Ne nutně ve vašem…)

Na straně serveru je to o něco jednodušší. Můžete si logovat neobvyklé stavy, můžete si podrobně diagnostikovat problémy a uživatelům sdělíte jen to, že se stalo něco špatně a že to napravíte. Ovšem na straně klienta je to obtížnější.

Klient má prohlížeč, v něm mu běží JavaScript, a ten má k chybám poměrně zvláštní postoj: mlčí. Donedávna si člověk všiml chyby v JavaScriptu jen když se díval, jestli tam nějaká nebyla, a když už se o ní dozvěděl, tak na ni leckdy nevěřícně koukal (známé „null má hodnotu null nebo není objekt. Řádka: 12, Znak 1182, Kód: 0“). Vývojáři mají k dispozici chybové konzole a dozvědí se (dnes už…) víc, ale uživatel?

Uživatel vidí chybu v JavaScriptu jako mysteriózní změnu chování, pro kterou není „zjevný“ důvod. Vše funguje až do určité chvíle, kdy například na něco klikne, nebo načte víc záznamů, a najednou přestanou některé funkce pracovat. Třeba už se nenačítají nové hodnoty. Přestane fungovat psaní. Nelze odeslat formulář. Nemůže kliknout na položku v menu. Stránka se celá rozsype. (Mezi nejmysterióznější chyby patří parse errors, které ukončí vykonávání skriptů vůbec, a uživatel nemá naprosto tušení, proč stránka, co ještě včera fungovala, najednou sice je vidět, ale nepracuje.)

Syntaktické apod. chyby totiž nevypíšou velké blikající „Něco je špatně, uživateli, kontaktuj administrátora!“, ale bez varování ukončí provádění skriptů (nebo způsobí ještě něco jiného) a nedají to nijak najevo. Vývojář se o tom z logu nedozví a zjistí to až z naštvaných mailů od uživatelů. A co si budeme povídat – většinou se dozví variaci na „Máte to rozbitý“.

Řešením by mohlo být zavírání celých skriptů do velkých bloků try…catch, ale chybí tomu jednak elegance, jednak to neřeší problém např. při načítání skriptů z jiných domén nebo skriptů bez tohoto „řešení“, a v neposlední řadě to je „ad hoc“ přístup, chybí mu univerzálnost.

window.onerror

V prohlížečích je možnost zachytit událost window.onerror, která je vyvolána při chybě – syntaktické, běhové, při neošetřené výjimce apod.

Podpora v prohlížečích je silně nevyvážená: IE tuto konstrukci podporuje od verze 5.5 (!), FF od verze 6, Chrome od verze 13, Safari od 5.1 a Opera od verze 11.60. Nelze to tedy nazvat jednoznačně „novinkou“.

Obsluha je jednoduchá. Systém předá obslužné funkci tři parametry: chybové hlášení, URL skriptu, ve kterém došlo k chybě, a číslo řádku.

window.onerror = function(message, url, line) {
  alert("Chyba: " + message + " na řádku " + line + " ve skriptu " + url);
}

Je (logicky) třeba, aby nastavení chybové obsluhy proběhlo dřív než samotná chyba. Tedy (pokud možno) v prvním načteném skriptu.

Obsluhu můžete nastavit i pro element <body>, podobně jako se nastavuje  onload:

<body onerror="alert('Chyba: ' + event + ' na řádku ' + lineno + ' ve skriptu ' + source)">

Co s chybou?

<nadsázka> Můžete ji zamlčet. Vy totiž chyby neděláte, a kdyby se vinou nedokonalé techniky do kódu dostala, tak se o tom nikdo nesmí dozvědět, tím míň neznalý uživatel – mohl by si pak myslet o autorovi bůhvíco! (To si bude myslet stejně…) </nadsázka>

window.onerror = function(){return false;}

 „Blikala nám tam kontrolka PORUCHA. Tak jsme ji přelepili a od té doby nemáme žádné poruchy hlášené…“ Za chybu vám nikdo hlavu neutrhne. Za tohle by se ale trhat měly!

Rozumný přístup je, samozřejmě, ten věcnější. Chybu můžete zachytit, můžete sdělit uživateli, že je něco špatně, upozornit ho, že za to nemůže on (a ani několikeré zmáčknutí F5 nepomůže), omluvit se, samozřejmě – a taky si můžete nechat poslat to hlášení, aby vám k něčemu bylo:

window.onerror = function(message, url, line) {
  if (window.XMLHttpRequest) {

    var xhr = new XMLHttpRequest();
    var logurl = "http://www.example.com/errorlog";
    var log = message + "n" + url + "n" + line;
    xhr.open("POST", logurl);
    xhr.setRequestHeader("Content-Type", "text/plain");
    xhr.send(log);
  }
  return false;
}

Případná syntaktická nebo běhová chyba nezpůsobí „zaseknutí“ celého JS engine (což vždy znamená „záhadné“ chyby a zmateného uživatele, který neví, co má dělat). Systém ji dokáže zachytit a zpracovat – tedy například takto poslat potřebné informace vývojáři. Pak už je třeba jen vhodně zareagovat a důstojně zhavarovat.

Důstojně zvládnout chybu je vždy to nejlepší možné řešení. A to platí nejen pro JavaScript.

Komentáře

Subscribe
Upozornit na
guest
13 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
Srigi

Prave vcera som pozeral prednasku Nicholasa Zakasa – Scalable JavaScript Application Architecture, kde sa aj okrajovo dotkol „handlovania“ chyb. Totiz napr. v PHP frameworkoch toto uz za nas vyriesili autori frameworkov, napr. tak ze do tzv. dispatch loop umiestnili ten velky try/catch blok.

JS aplikacie su ale riadene diametralne odlisne, akcie od uzivatela malokedy idu cez nejaky centralny FrontController. Skor sa v nich stretneme s tzv. PubSub technikou spracovania poziadaviek. A prave v Zachovej prednaske mozno najst drobny snippet ako to mozno riesit. Nejaky Core pri instancovani modulu prejde vsetky metody modulu a obali ich try/catch blokom, aby ich Core zachytil.

Ale priznam sa, ze aj window.onerror nevypada na zlu techniku, otazkou je ako je tato technika prenositelna, ked window nie je nativny objekt a u Node.js s nou asi zatial nepochodime.

Oldisy3

Tak dnes musim pochvalit. Tohle se mi opravdu hodi.

Ajax

Perfetkni rada, diky!

Gappa

„Podpora v prohlížečích je silně nevyvážená: IE tuto konstrukci podporuje od verze 5.5 (!), FF od verze 6, Chrome od verze 13, Safari od 5.1 a Opera od verze 11.60. Nelze to tedy nazvat jednoznačně „novinkou“.“

Neřekl bych, že Firefox podporuje až od verze 6, protože v logu generovaném právě pomocí onerror mám několik z Firefox/3.6.23 a na StackOverflow to podle komentářů funguje i v 3.0.x :)

Info o chybě posílám pomocí „new Image“ způsobu, ale to je celkem už detail. Spíš mám problém s tím, že tam je strašné množství balastu a chyb, za které (předpokládám) nemůže web.

Jedná se např. o chyby XUL rozhraní ve Firefoxu, „error loading script“ od zablokovaného načítání ga.js nebo fb skriptů a pak také „různé divnoty“ při přesměrování z výsledků vyhledávání googlu – že nelze načíst script z např. takového url: http://d3lvr7yuk4uaui.cloudfront.net/items/domains/f/{nazev_domeny}.js

Každopádně je to užitečná věc, kterou by lidé měli znát :)

nothrem

Tohle je právě problém odchytávání „všech chyb“. Moderní prohlížeče bez výjimky podporují rozšíření, které běží na JS ve stejném scopu.
Pak musíte rozlišit, co je skutečně vaše chyba a co je chyba pluginu (např. zmíněná chyba s „{nazev_domeny}.js“ je chyba pluginu Babylon Pro translator, který jede metodou pokus-omyl).
Pozor také na to, že nejnovější verze prohlížečů vracejí ‚záhadnou‘ chybu „Scripr error. file: index.html, line: 0“, která v překladu znamená „chyba je ve skriptu, ke kterému kvůli bezpečnosti nemáte práva“ (a tudíž ji můžete ignorovat).

BTW nechápu proč je článek tak dlouhý, když stačilo napsat „Chyby chytejte ve window.onerror a pak si je pošlete přes AJAX nebo IMAGE na server.“ a přidat dva příklady.

Gappa

Díky za doplnění a info o té chybě :)

Čtenář

Po kliknutí na odkaz v RSS čtečce mě server přivítal hláškou: „An internal server error occurred. Please try again later.“

Riny

Mně se to zas stalo, když jsem si chtěl zobrazit diskuzi (očividně už tu ale jsem :3) — pobavilo XD.

odhlasit

Co se týče první části článku, pojednávající o srozumitelném vyjádření chyby, tak to je problém, se kterým se často potýkají i velké firmy. A je až s podivem, kam až je možné zajít.

Nedávno jsem měl sen. Přál jsem si úspěšně se přihlásit do služby Windows Live v jedné hře, abych si mohl zahrát online. Nic víc, nic míň. Prostředí Windows Live dostupné přímo ve hře mi při pokusu o připojení sdělovalo Nelze se přihlásit. Fajn. Přidány výjimky do firewallu. Nelze se přihlásit. Po další marné snaze jsem spustil desktopový klient, který mi nejen sdělil, že se nelze přihlásit, ale zároveň vypsal i několikaciferné číslo chyby, které však nebylo nikde na webu k nalezení. Fajn. Desktopový klient měl ještě jednu výbornou funkci – vygeneroval odkaz s názvem Vyřešte problém kliknutím sem. Klikám, spouští se IE9, načítání stránky končí se slovy Nelze načíst rámce stránky. Fajn. Přihlásím se do Windows Live přes webové rozhraní – bez problému. Nikde ani náznak nějakého problému nebo jeho řešení. Na stránce je mj. zobrazen banner s nabídkou na rozšíření stávajícího účtu o nové XBox Live funkce. Sice XBox nemám, chci si zahrát na PC, ale ze zoufalosti nabídku odkliknu a světe div se, každé přihlášení je odteď úspěšné. Takže suma sumárum tři hodiny zkoušení, jestli tohle nebo tohle není náhodou ten problém, a to jenom díky tomu, že žádná ze tří aplikací postavených nad touto službou mi nebyla schopná sdělit, z jakého důvodu přihlášení neuspělo. Asi jsem toho chtěl v roce 2012 moc.

windowsupdate

Já jsem měl noční můry z chyb při windows updatech na WinXP na windowsupdate­.microsoft.com. „Aktualizace se nezdařila, chyba: 0x8…“. Na webu bylo k nalezení o takovýchto chybách prd, přičemž ruční instalace aktualizace pak většinou v pohodě (navíc v případě chyby to v GUI napsalo chybu textově, a ne jen debilním číslem s odkazem na web, kde ovšem nebylo vysvětlení vůbec žádný – a v logu služby taky prd a vořech k identifikaci) – ovšem to je řešení zcela nepraktický a pomalý, ale naštěstí to vždy řešily nějaký prográmky, co celou službu a navázaný procesy na ní „restartovaly“ do základního stavu, a pak to prošlo.

Tom

Díky za článek.
O tom, že existuje událost onerror jsem neměl tušení.
Tom

Ivan Novakov

A co se stane, pokud nastane chyba v onerror callbacku? :)

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.