chevron-left chevron-right

Piotr Nalepa Frontend, architektura i AI

Cykle życia strony internetowej. Jak reagować na zmiany za pomocą JavaScript?

Ta wersja
blog.piotrnalepa.pl/2019/02/28/cykle-zycia-strony-internetowej-jak-reagowac-na-zmiany-za-pomoca-javascript
Opublikowano
Autor
, Staff Software Engineer
Kategoria
JavaScript
Uwagi
Napisz do mnie · Napisz na X

Ten wpis ma 7 lat. Od tego czasu przeglądarki i narzędzia mogły się zmienić, więc zanim użyjesz kodu, sprawdź go z aktualną dokumentacją.

Kiedy mówimy o cyklach życia, zazwyczaj mamy przed oczami: dorastanie, bycie dorosłym i starzenie się. W przypadku stron i aplikacji internetowych działających w przeglądarkach można by użyć luźnego powiązania z tymi cyklami. Oczywiście strona nie będzie dorastała ani starzała się w trakcie jednej sesji użytkownika. Brzmi kontrowersyjnie? Na pewno tak, ale więcej można się dowiedzieć w dalszej części tekstu.

Sekcja 1Cykle życia strony internetowej w przeglądarce

Strona internetowa opiera się na HTML i może wykorzystywać JavaScript. Dlatego też, istnieje takie pojęcie jak event, czyli zdarzenie które zostało wywołane w kodzie JavaScript. Każda strona/aplikacja internetowa otwarta w przeglądarce może reagować na trzy takie eventy związane z istnieniem strony:

  1. DOMContentLoaded,
  2. load,
  3. beforeunload/unload.

Te trzy zdarzenia zawsze się pojawiają w przypadku poprawnie działającej strony. Każdy z nich jest odpalany w innym momencie. Dzięki czemu, jesteśmy w stanie odpowiednio zareagować w naszych skryptach JavaScript. Z własnego doświadczenia wiem, że najczęściej się korzysta z obsługi zdarzenia load. Dlaczego? Wyjaśnienie znajdziesz poniżej.

Sekcja 2Zdarzenie DOMContentLoaded

Zdarzenie DOMContentLoaded jest uruchamiane w momencie wczytania kodu HTML całej strony. To również oznacza, że tutaj nie musimy czekać na załadowanie się wszystkich skryptów JS, obrazków czy stylów CSS. Jest ono rzadko wykorzystywane w procesie tworzenia strony internetowej czy też aplikacji internetowej. Przykładem wykorzystania takiego eventu może być: sprawdzenie czy serwer zwrócił stronę z błędem po wysłaniu formularza wyświetlonego w iframe, aby następnie móc to obsłużyć poza iframe'em. Przykładowy kod obsługujący to zdarzenie wygląda następująco:

Przykład 1JavaScript
const popup = window.document.querySelector('#popup');
const form = popup.querySelector('form');
const iframe = popup.querySelector('iframe');
const checkIsSuccess = (event) => {
    const errorMessage = iframe.contentDocument.querySelector('.error-message');

    if (errorMessage) {
        window.document.body.classList.add('has-error');

        return;
    }

    window.document.body.classList.remove('has-error');
    window.document.body.classList.add('has-success');
    popup.remove();
}

iframe.contentDocument.addEventListener('DOMContentLoaded', checkIsSuccess, false);

form.submit();

Sekcja 3Zdarzenie load

To zdarzenie jest uruchamiane w momencie, gdy wszystkie zależności pliku HTML, takie jak obrazki, skrypty i style zostały pobrane przez przeglądarkę (błąd pobrania któregokolwiek z plików nie powstrzymuje przeglądarki przed odpaleniem tego zdarzenia). Wcześniej wspomniałem, że zdarzenie load jest najczęściej wykorzystywane, dzieje się tak dlatego, że wtedy dopiero jesteśmy w stanie mieć pewność, że wszystkie nasze zależności zostały pobrane i możemy urochomić odpowiednie skrypty JS które wzbogacą nasz interfejs na przykład o funkcjonalność galerii zdjęć. Nasłuchiwać zdarzenie load możemy na kilka sposobów:

Sekcja 3.1Skrypt samowykonujący się

Przykład 2JavaScript
(function() {
    // kod który ma się uruchomić po pełnym załadowaniu strony
})();

Jest to najpopularniejsze podejście. Sam z niego najczęściej korzystam.

Sekcja 3.2Nasłuchiwanie w addEventListener

Przykład 3JavaScript
const initGallery = () => { /* kod uruchamiający galerię po załadowaniu strony */ };

document.addEventListener('load', initGallery, false);

Sekcja 3.3Przypięcie obsługi zdarzenia bezpośrednio pod własność obiektu document

Przykład 4JavaScript
window.document.onload = initGallery;

Jest to najrzadziej stosowane podejście, bo w ten sposób podepniemy tylko jedną funkcję pod zdarzenie.

Sekcja 3.4Ciekawostka

Zdarzenie load może być wywołane nie tylko na obiekcie document, ale również na elementach HTML związanych z <img /> oraz <video />. Dzięki temu jesteśmy w stanie wykryć moment w którym dane zdjęcie bądź plik wideo się załaduje na stronie. Do obsługi tego zachowania polecam stosowanie następującego podejścia:

Przykład 5JavaScript
const image = window.document.querySelector('img');
const doSomething = () => {};

image.onload = doSomething;

Sekcja 4Zdarzenie beforeunload/unload

Zdarzenie beforeunload jest uruchamiane w momencie próby zamknięcia strony w zakładce przeglądarki. Za jego pomocą możemy wykonać wiele akcji które w końcowym zamyśle pozwolą na przykład, na zachowanie stanu aplikacji lub upewnienie się, że użytkownik na pewno chce zaniechać pewnej czyności na stronie. Co ważne, obsługę tego zdarzenia możemy sobie zapewnić tylko poprzez podpięcie własnej funkcji do własności obiektu document.

Przykład 6JavaScript
window.onbeforeunload = function () {
    // jeśli użytkownik potwierdzi że chce zapisać stan aplikacji
    if (confirm("Czy chcesz zapisać obecny stan formularza na później?")) {
        const inputs = document.getElementsByTagName('input');

        // zapisz wartości pól z formularza w localStorage
        localStorage['input-jeden'] = inputs[0].value;
        localStorage['input-dwa']   = inputs[1].value;
    }
};

Powyższe zagadnienie już poruszałem swego czasu na blogu, gdzie prezentowałem prosty skrypt JavaScript do obsługi zapisu stanu formularzy

Sekcja 5Bonusowe zdarzenia

Oprócz powyższych zdarzeń związanych bezpośrednio z procesem ładowania treści na stronie możemy również obsłużyć szereg innych zdarzeń. Między innymi:

  • visibilitychange - za pomocą tego zdarzenia możemy wykryć moment w którym użytkownik przełączył się na inną zakładkę w przeglądarce lub zminimalizował okno przeglądarki. Na blogu poruszałem już to zagadnienie w artykule dotyczącym synchronizacji wideo między dwiema zakładkami przeglądarki.
  • resize - to zdarzenie jest uruchamiane w momencie zmiany szerokości okna przeglądarki. Bywa przydatne, lecz jego użycie wymaga odpowiedniego podejścia jeśli chcemy obliczać odpowiednią pozycję elementu w interfejsie aplikacji czy strony internetowej. Ten event odpala się bardzo często co może powodować spadki wydajności w przypadku nieprawidłowej obsługi tego zdarzenia.
  • transitionend - to zdarzenie jest bardzo ciekawe, bo niejako łączy ze sobą świat CSS i JavaScript. Za jego pomocą możemy obsłużyć moment, w którym zakończy się animacja przejścia między dwiema wartościami wybranej własności CSS. W CSS ustawiamy transition: background 0.5s linear; jako styl wybranego elementu, a następnie możemy to obsłużyć w JS za pomocą: element.addEventListener('transitionend', doSomething, false);.
  • observery - to poniekąd nie są zdarzenia, lecz całe API udostępnione w specyfikacji HTML5. Zaliczamy do nich: MutationObserver czy też ResizeObserver. MutationObserver jest używany gdy chcemy sprawdzić czy nastąpiły zmiany w drzewie DOM, np. dodaliśmy nowy element HTML do drzewa lub zmieniliśmy wartość atrybutu HTML. ResizeObserver wykorzystujemy gdy chcemy obsługiwać zmianę wymiarów danego elementu i na tej podstawie wykonywać jakieś akcje w aplikacji. Więcej na temat observerów możesz przeczytać w tekście dotyczącym obserwacji zmian wartości atrybutów elementów DOM.

Sekcja 6Podsumowanie

Tworząc strony internetowe czy aplikacje internetowe jest bardzo ważne, aby wiedzieć co się dzieje z interfejsem w danym momencie. Dzięki temu możemy reagować na różne sytuacje i często dzięki temu możemy zoptymalizować działanie interfejsu poprzez wyłączanie/włączanie pewnych funkcjonalności. Mam nadzieję, że tym wpisem udało mi się zaspokoić Twoją ciekawość i będziesz w stanie wykorzystać tą wiedzę w swoich projektach.

Tekst ten dedykuję mojemu Tacie, który odszedł w minione wakacje.

Udostępnij
Uwagi

O autorze

Staff Software Engineer

Piszę na tym blogu od 2009 roku, a strony i aplikacje webowe tworzę zawodowo od 14 lat. Obecnie w Bishop Fox prowadzę frontend platformy Cosmos, od samego początku projektu. Wcześniej pracowałem m.in. w OLX, KUDO, Auto1 i eZ Systems. Piszę tu o tym, czego nauczyłem się w praktyce: o JavaScripcie, TypeScripcie, Reakcie, CSS-ie i architekturze frontendu. Występowałem też jako prelegent na konferencjach w Polsce i Europie. Masz pytanie albo pomysł na wpis? Daj znać!