JS defer - klucz do szybszej strony? Sprawdź, jak to działa!

Logo JS obok kodu w JavaScript, który zawiera funkcję loterii. `js defer` w kodzie pozwala na asynchroniczne ładowanie skryptów.

Napisano przez

Alex Jabłoński

Opublikowano

5 maj 2026

Spis treści

Wydajność strony często rozbija się o kilka linijek HTML i jedną decyzję: kiedy przeglądarka ma pobrać oraz uruchomić skrypt. Temat, który często trafia do rozmów o wydajności frontendu i bywa skrótowo opisywany jako js defer, dotyczy właśnie tego porządku: HTML może się parsować bez przerwy, a JavaScript startuje dopiero wtedy, gdy DOM jest już gotowy. Ja traktuję to jako jedno z prostszych i najbardziej opłacalnych usprawnień, bo zmniejsza ryzyko błędów i poprawia odczuwalną szybkość ładowania.

Najważniejsze zasady użycia atrybutu defer

  • Defer pobiera skrypt równolegle z parsowaniem HTML, ale wykonuje go dopiero po zakończeniu parsowania.
  • Kolejność plików jest zachowana, więc można bezpiecznie ładować zależne od siebie skrypty.
  • Działa tylko dla zewnętrznych skryptów z `src`; w skryptach inline nie ma efektu.
  • Nie jest tym samym co async i nie rozwiązuje każdego problemu z wydajnością.
  • Moduły ES mają to zachowanie domyślnie, więc `defer` nie daje im dodatkowej korzyści.
  • Najlepiej sprawdza się tam, gdzie kod dotyka DOM albo zależy od kolejności ładowania.

Jak działa defer i co dokładnie zmienia

Atrybut `defer` mówi przeglądarce, żeby pobrała skrypt bez blokowania parsowania HTML, ale nie uruchamiała go od razu. Kod wykonuje się dopiero wtedy, gdy dokument został już przeanalizowany, a DOM istnieje w pełnej postaci. To ważne, bo wiele błędów frontowych bierze się właśnie z tego, że skrypt próbuje odwołać się do elementu, którego jeszcze nie ma na stronie.

W praktyce wygląda to tak: plik JS może zacząć się pobierać już w `

`, ale przeglądarka nie zatrzyma przez to budowania strony. Gdy HTML zostanie sparsowany, skrypt uruchomi się przed zdarzeniem `DOMContentLoaded`, a jeśli masz kilka plików z `defer`, zostaną wykonane w tej samej kolejności, w jakiej pojawiają się w dokumencie.

  
  

To jest szczególnie wygodne, gdy najpierw ładujesz bibliotekę albo warstwę pomocniczą, a dopiero potem kod aplikacji. Warto też pamiętać o dwóch ograniczeniach: `defer` ma sens dla skryptów z `src`, a dla modułów ES jest w praktyce zbędny, bo moduły i tak działają podobnie domyślnie. Z tego powodu często lepiej myśleć o nim jako o narzędziu do klasycznych plików JS niż o uniwersalnym przełączniku. Skoro już wiesz, co robi od środka, pora zestawić go z innymi sposobami ładowania skryptów.

Wykres porównuje czas ładowania stron, pokazując, jak js defer wpływa na JavaScript, parsowanie i inne etapy.

Defer, async i klasyczne skrypty nie rozwiązują tego samego problemu

Najwięcej nieporozumień bierze się stąd, że te trzy opcje brzmią podobnie, ale w praktyce ustawiają zupełnie inny moment wykonania. Ja zwykle porównuję je nie pod kątem tego, czy „przyspieszają stronę”, tylko co dokładnie blokują, kiedy startują i czy można liczyć na kolejność.
Opcja Kiedy przeglądarka pobiera plik Kiedy wykonuje kod Czy kolejność jest przewidywalna Najlepsze zastosowanie
Klasyczny ` W momencie napotkania tagu Od razu, z przerwaniem parsowania Tak, ale kosztem blokowania HTML Rzadko, głównie dla bardzo małych krytycznych fragmentów
` Równolegle z parsowaniem HTML Po sparsowaniu dokumentu Tak Skrypty zależne od DOM i od siebie nawzajem
` Równolegle z parsowaniem HTML Gdy tylko plik się pobierze Nie Niezależne widgety, statystyki, zewnętrzne integracje
` Równolegle z parsowaniem HTML Po sparsowaniu, podobnie jak `defer` Zwykle tak, w ramach modelu modułów Nowoczesne aplikacje oparte na ES modules

Najpraktyczniejsza różnica jest taka: `defer` pozwala pobrać skrypt wcześnie, ale uruchamia go późno. To często daje lepszy efekt niż wrzucenie tagu na sam dół `

`, bo wtedy pobieranie pliku startuje dopiero po przejściu przez cały HTML. W małych projektach to może nie robić wielkiej różnicy, ale w większych aplikacjach i przy wolniejszym łączu potrafi być odczuwalne. Jeśli chcesz, by kod nie blokował renderowania, a jednocześnie był gotowy, gdy DOM już istnieje, `defer` zwykle wygrywa z klasycznym podejściem.

Kiedy używam defer, a kiedy zostawiam inny sposób ładowania

Najczęściej sięgam po `defer`, gdy skrypt ma coś zrobić z gotową strukturą strony: podpiąć event listenery, zainicjować komponenty, wypełnić menu, uruchomić walidację formularza albo podłączyć kilka zależnych od siebie plików. To dobry wybór także wtedy, gdy kod jest rozbity na warstwy: biblioteka, narzędzia pomocnicze i właściwa logika aplikacji.

W praktyce traktuję `defer` jako domyślne rozwiązanie dla zewnętrznych skryptów aplikacyjnych, które nie muszą wejść do akcji zanim dokument się zbuduje. Jeśli elementy interfejsu istnieją dopiero po parsowaniu HTML, wcześniejsze uruchomienie kodu nie daje żadnej korzyści, a tylko zwiększa ryzyko błędu.

Gdzie daje najlepszy efekt

  • Skrypty inicjalizujące interfejs po stronie klienta.
  • Pliki zależne od kolejności, na przykład biblioteka i kod aplikacji.
  • Duże bund­le, które nie muszą blokować pierwszego renderu.
  • Rozwiązania, w których kod odwołuje się do elementów DOM, stylów lub atrybutów strony.

Przeczytaj również: JavaScript - Jak czytać i pisać kod bez chaosu?

Kiedy lepiej wybrać coś innego

  • Gdy skrypt jest całkowicie niezależny i może wejść do akcji natychmiast po pobraniu.
  • Gdy używasz modułów ES i nie potrzebujesz dodatkowego sterowania kolejnością.
  • Gdy fragment JS jest naprawdę mały i krytyczny dla pierwszego ekranu.
  • Gdy mówimy o inline script bez `src`.

Tu jest ważny niuans: `defer` nie sprawia, że kod staje się „lekki”. On tylko przesuwa moment wykonania. Jeśli sam skrypt wykonuje ciężką pracę, nadal może spowolnić interakcję tuż po parsowaniu HTML. Dlatego ja patrzę na ten atrybut jako na sposób na uporządkowanie startu, a nie jako cudowną metodę na ciężki JavaScript. To prowadzi do typowych błędów, które widzę najczęściej podczas wdrażania tej techniki.

Najczęstsze błędy, które psują efekt

Najbardziej kosztowny błąd to założenie, że `defer` działa wszędzie tak samo. Nie działa. Jeśli skrypt jest osadzony inline, atrybut nie daje praktycznie nic. Jeśli kod jest modułem, efekt jest już zapewniony przez sam model modułów. Jeśli do tego dorzucisz `async` obok `defer`, przeglądarka i tak potraktuje tag tak, jakby miał tylko `async`.

  • Mylenie `defer` z opóźnieniem do końca ładowania strony - skrypt uruchamia się po parsowaniu HTML, ale przed `DOMContentLoaded`, nie „po wszystkim”.
  • Zakładanie, że działa dla inline script - bez `src` nie ma realnego efektu.
  • Ignorowanie kolejności plików - `defer` ją zachowuje, więc zmiana kolejności w HTML nadal ma znaczenie.
  • Łączenie z `async` bez zamiaru - jeśli oba są obecne, `async` wygrywa.
  • Używanie go jako zamiennika optymalizacji kodu - ciężki JS nadal trzeba uprościć, podzielić albo odłożyć.

Ja szczególnie pilnuję jednego scenariusza: gdy ktoś przenosi skrypt z końca `

` do `` i dodaje `defer`, a potem zapomina przetestować inicjalizację. Wtedy kod, który wcześniej działał przypadkiem dzięki położeniu w HTML, nagle wymaga poprawnego dostępu do DOM, selektorów i zależności. To nie jest wada `defer`, tylko moment, w którym wychodzi na jaw, że aplikacja była oparta na szczęściu, a nie na porządnym cyklu ładowania. Da się temu łatwo zapobiec, jeśli wdrożyć zmianę metodycznie.

Jak wdrożyć to poprawnie w projekcie

Jeśli miałbym zrobić to w prosty, bezpieczny sposób, zacząłbym od jednego pytania: czy ten skrypt naprawdę musi działać przed zbudowaniem DOM? W większości stron odpowiedź brzmi „nie”. Wtedy przenoszę plik do `

`, dodaję `defer`, sprawdzam zależności i testuję kolejność uruchamiania.
  1. Wydziel wszystkie zewnętrzne pliki JS, które zależą od struktury strony.
  2. Dodaj `defer` do tagów `
  3. Ustaw kolejność plików zgodnie z zależnościami, nie tylko zgodnie z estetyką HTML.
  4. Przenieś inicjalizację interfejsu do kodu, który działa po parsowaniu DOM.
  5. Sprawdź konsolę i testuj na wolniejszym łączu, żeby zobaczyć realny moment wykonania.

Przykład praktyczny: jeśli mam bibliotekę pomocniczą i własny kod aplikacji, ustawiam je tak, aby biblioteka była pierwsza, a dopiero potem warstwa inicjalizująca UI. Dzięki temu nie muszę doklejać ręcznych opóźnień, czekać na dodatkowe eventy ani pisać zbędnych wrapperów. W wielu projektach to wystarcza, żeby usunąć przypadkowe błędy związane z kolejnością ładowania. Po wdrożeniu warto jeszcze wykonać jeden krok, którego sporo osób pomija: sprawdzić, co dzieje się z innymi zasobami strony.

Co jeszcze sprawdzam po przełączeniu skryptów na opóźnione ładowanie

Po zmianie sposobu ładowania nie kończę pracy na samym tagu `

Jeśli projekt jest większy, patrzę też na podział kodu: czy wszystkie moduły muszą być ładowane na starcie, czy część z nich da się uruchomić dopiero po interakcji użytkownika. Sam `defer` poprawia start, ale nie zastępuje rozsądnego cięcia bundle'a ani nie rozwiązuje problemu nadmiarowego JavaScriptu. Najlepszy efekt daje połączenie prostego ładowania, dobrej kolejności plików i odciążenia rzeczy, które nie są potrzebne od pierwszej sekundy.

Właśnie dlatego traktuję `defer` jako domyślny wybór dla skryptów, które mają czekać na gotowy DOM, ale nie chcą blokować użytkownika. To małe ustawienie, a często robi większą różnicę niż kolejne kosmetyczne poprawki w HTML.

FAQ - Najczęstsze pytania

Atrybut `defer` instruuje przeglądarkę, aby pobierała skrypt równolegle z parsowaniem HTML, ale wykonała go dopiero po zakończeniu parsowania dokumentu. Dzięki temu HTML nie jest blokowany, a skrypt ma dostęp do gotowego DOM.

Główna różnica to kolejność i moment wykonania. `defer` gwarantuje wykonanie skryptów w kolejności ich wystąpienia w HTML, po sparsowaniu DOM. `async` wykonuje skrypt natychmiast po pobraniu, niezależnie od kolejności i stanu DOM, co może prowadzić do nieprzewidywalnych rezultatów.

Najlepiej używać `defer` dla skryptów, które zależą od struktury DOM (np. inicjalizują interfejs, manipulują elementami) i dla których kolejność wykonania jest ważna. Jest to domyślne rozwiązanie dla większości zewnętrznych skryptów aplikacyjnych.

Nie, atrybut `defer` nie ma praktycznego zastosowania dla skryptów inline (bez atrybutu `src`). Działa on wyłącznie dla zewnętrznych plików JavaScript, które są pobierane przez przeglądarkę.

Oceń artykuł

Ocena: 0.00 Liczba głosów: 0

Tagi:

js defer jak działa atrybut defer defer a async defer w skrypcie kiedy używać defer

Udostępnij artykuł

Alex Jabłoński

Alex Jabłoński

Nazywam się Alex Jabłoński i od 9 lat zajmuję się programowaniem webowym. Moja przygoda z tą dziedziną zaczęła się od prostych projektów, które z czasem przerodziły się w pasję do tworzenia użytecznych i estetycznych aplikacji internetowych. Fascynuje mnie nie tylko sam proces kodowania, ale także to, jak technologie wpływają na nasze życie i jak możemy je wykorzystać, aby rozwiązywać codzienne problemy. Piszę o różnych aspektach programowania, od podstawowych języków po bardziej zaawansowane techniki i narzędzia. Staram się, aby moje teksty były przystępne i zrozumiałe, a skomplikowane zagadnienia przedstawiam w prosty sposób. Regularnie śledzę nowinki w branży, co pozwala mi dostarczać aktualne i rzetelne informacje. Moim celem jest nie tylko edukacja, ale także inspirowanie innych do rozwijania swoich umiejętności w programowaniu.

Napisz komentarz