Kawałek Kodu

Każdy z nas był kiedyś malcem i marzyło mu się zostać strażakiem, policjantem, kierowcą wozu asenizacyjnego lub celował wyżej, chcąc być rycerzem. Dziś już raczej nikt z czytelników tego bloga nie jest przedszkolakiem, a jako dorosła osoba została policjantem, strażakiem, kierowcą wspomnianego wozu, pewnie informatykiem, ale mało kto został rycerzem. Teraz już na to są małe szanse, szczególnie kiedy bronią jest komputer. Ale i na to da się coś poradzić.

window.onZawisza = function() {}

Podobno na Zawiszy można było polegać i mieć do niego pełne zaufanie. Niestety z jego pomocy już nie skorzytamy programując w JS, ale jest jego godny następca. A co lepsze ma możliwości bilokacji, bowiem może kontrolować nasz kod JS w kilku przeglądarkach, i to wcale nie naszych!

O czym mowa? O zdarzeniu error i jego obsłudze. Pewnie nie miałeś o nim okazji tyle słyszeć, co o wszędobylskich click, mousemove czy submit. A jest równie ciekawe. W zależności od tego jaki błąd zostanie wywołany i jego miejsce zainicjowania mam dwie możliwości obsługi:

  • obsługa błędów składni i wyjątków poprzez atrybut onerror obiektu window lub poprzez podpięce handlera błędów do tego obiektu,
  • obsługa błędów ładowania elementów typu IMG, AUDIO, VIDEO czy SCRIPT, analogicznie jak wyżej, ale po podpięciu do konkretnego elementu.

W przypadku błędów drugiego typu nie bąbelkują w górę drzewa DOM, więc nie obsłużymy ich w obiekcie window. To co jest ciekawe, że w zależności od umiejscowienia handlera obsługi błędu uda nam się wyłapać błąd lub nie.

Przykład:

<script>
  a =;
</script>

<script>
  window.addEventListener('error', function(e){
    console.log(e);
  });

  let a = 1;
  a = a - b;
</script>

W tym przypadku nie wyłapiemy błędu składni w pierwszym skrypcie, bo występuje wyżej w kodzie, ale uda nam się wyłapać drugi błąd (ta błąd referencji i nie powoduje błędu kompilacji), bo handler i drugi błąd występują w należytej kolejności.

 

<script>
  a =;

  window.addEventListener('error', function(e){
    console.log(e);
  });

  let a = 1;
  a = a - b;
</script>

Ten przykład wydaje się podobny do pierwszego, ale przez pierwszy błąd składni skrypt nie zostanie skompilowany, a więc nie będzie obsługi błędu.

 

<script>
  window.addEventListener('error', function(e){
    console.log(e);
  });

  let a = 1;
  a = a - b;
</script>

<script>
  a =;
</script>

W trzecim przykładzie obsłużymy obydwa błędy, bo pierwszy nie powoduje błędu kompilacji, a drugi zostanie wywołany kiedy już działa handler.
Najpewniej jest po prostu wywołać handler jako pierwszy skrypt na naszej stronie, w odrębnym skrypcie.

Gadał dziad do obrazu, a obraz do niego ani razu.

W przypadku obrazków można w fajny sposób obsłużyć problem z załadowaniem pliku źródłowego. Załóżmy, że mamy odwołanie do pliku jak poniżej:

<img src="qwerty.gif"/>

Plik ten z jakiegoś powodu nie załadował się. Wystarczy, że dodamy obsługę zdarzenia error na tym elemencie:

<img src="qwerty.gif" onerror="this.error=null;this.src='obrazek.gif'"/>

Dlaczego w tym przypadku użyłem wewnętrznego handlera elementu? Jeśli dodałbym handler analogicznie jak w przypadku obiektu window, czyli anonimową funkcję, to nie mógłbym jej usunąć wewnątrz metody removeEventListener, bo do niej muszę dostarczyć referencję funkcji. Oczywiście można to zrobić deklarując funkcję na zewnątrz handlera. Mając wtedy referencję na nią, możemy użyć jej zarówno w podpinaniu, jak i odpinaniu listenera.

A po co w ogóle odpinać listener? Gdyby zdarzyło się, że "obrazek.gif" również by się nie załadował, wpadlibyśmy w nieskończoną pętlę.

Pokaż rycerzyku, co masz w pancerzyku.

W tym momencie warto by było pokazać co właściwie otrzymujemy kiedy przechwycimy błąd. W przypadku obiektów medialnych zwracany jest po prostu obiekt Event. Natomiast w przypadku błędów na poziomie obiektu window, otrzymujemy obiekt ErrorEvent. O ile w tym pierwszym przypadku nie ma w środku nic ciekawego, bo przecież wiemy co konkretnie spowodowało błąd (no chyba, że chcielibyśmy wiedzieć dlaczego obrazek nie załadował się, ale takiej informacji brak), to w przypadku drugiego obiektu mamy kilka ciekawych właściwości:

  • message - czyli treść błędu,
  • filename - URL pliku, w którym wystąpił błąd,
  • lineno - numer wiersza z błędem,
  • colno - numer kolumny z błędem.

Mając te informacje i wiążąc je z tytułem wpisu, można w prosty sposób "debugować" stronę na przeglądarce, do której nie mamy dostępu. Wystarczy w obsłudze błędu użyć żądania ajax'owego lub Fetch API, wysłać dane do skryptu serwerowego, a tam zapisać je w pliku logów lub wysłać mailem. Nic nie stoi na przeszkodzie, aby błędy wysyłać również do Google Analitycs i śledzić je bezpośrednio w tym narzędziu.

Zbroję na ramię i do przeczytania!

 

Przydatne linki:
Błąd error wedle dokumentacji Mozilla.