Co zrobić, gdy skrypty JavaScript blokują ładowanie strony
Strona może mieć dobry serwer, lekkie grafiki i poprawny HTML, a mimo to startować ospale. Bardzo często winowajcą jest JavaScript blokujący renderowanie: skrypt pobierany zbyt wcześnie, wykonywany w złym momencie albo ładowany na każdej podstronie, choć realnie potrzebny jest tylko w jednym miejscu. Użytkownik widzi wtedy biały ekran, opóźniony nagłówek, niedziałające menu albo stronę, która „już wygląda”, ale jeszcze nie reaguje.
Najgorsze w tym problemie jest to, że nie zawsze widać go w biurze na szybkim łączu i mocnym laptopie. Wychodzi dopiero na telefonie, przy słabszym procesorze, na sieci LTE albo w danych z PageSpeed Insights, Lighthouse, Chrome DevTools i raportów Core Web Vitals. Dlatego nie zaczyna się od zgadywania. Najpierw trzeba ustalić, który skrypt naprawdę blokuje start strony, a dopiero później decydować, czy go odroczyć, podzielić, usunąć, przenieść, czy zostawić w spokoju.
Jak rozpoznać, że JavaScript faktycznie blokuje ładowanie strony
Pierwszy objaw to opóźnione pierwsze wyrenderowanie strony. Użytkownik wpisuje adres, przeglądarka pobiera HTML, ale zanim pokaże treść, musi jeszcze pobrać i wykonać część skryptów. Typowy podejrzany wygląda tak:
<head>
<script src="/js/app.js"></script>
</head>
Taki skrypt umieszczony w sekcji <head> bez defer lub async potrafi zatrzymać parsowanie dokumentu. Przeglądarka musi go pobrać, przetworzyć i wykonać, zanim pójdzie dalej. Jeżeli plik ma 300–800 KB po kompresji, importuje bibliotekę UI, kilka trackerów i jeszcze obsługuje elementy, których nie ma na pierwszym ekranie, efekt jest prosty: strona czeka na JavaScript.
Najpierw sprawdź trzy miejsca:
- PageSpeed Insights – szczególnie komunikaty typu „wyeliminuj zasoby blokujące renderowanie”, „usuń nieużywany JavaScript”, „ogranicz czas wykonywania JavaScriptu”.
- Chrome DevTools → Performance – nagraj ładowanie strony i zobacz, czy główny wątek jest zajęty długimi zadaniami.
- Chrome DevTools → Coverage – sprawdź, ile kodu JS zostało pobrane, ale nieużyte podczas pierwszego ładowania.
Dane, na które warto patrzeć, to przede wszystkim:
- LCP – powinien mieścić się w okolicach 2,5 sekundy lub mniej dla większości wizyt. Jeżeli główny nagłówek albo obraz hero pojawia się późno, JavaScript może opóźniać renderowanie.
- INP – dobry wynik to około 200 ms lub mniej. Jeżeli strona po kliknięciu reaguje z opóźnieniem, problemem może być przeciążony główny wątek.
- TBT w Lighthouse – nie jest bezpośrednio Core Web Vital, ale dobrze pokazuje, czy JavaScript blokuje interakcje podczas ładowania.
- rozmiar paczki JS – sam rozmiar nie przesądza o winie, ale plik powyżej kilkuset kilobajtów na start powinien zapalić lampkę ostrzegawczą.
- czas wykonywania JS – czasem mniejszy plik szkodzi bardziej niż większy, jeśli wykonuje ciężkie operacje od razu po starcie.
Praktyczna zasada: jeżeli skrypt nie jest potrzebny do pokazania treści widocznej na pierwszym ekranie, nie powinien blokować pierwszego renderowania. Menu, koszyk, slider, formularz, mapa, czat, widget opinii, analityka, remarketing — każdy z tych elementów trzeba potraktować osobno. Nie wszystko ma taki sam priorytet.
Dlaczego skrypty opóźniają renderowanie i które z nich naprawiać w pierwszej kolejności
JavaScript blokuje ładowanie strony na dwa sposoby. Pierwszy problem to pobieranie pliku w krytycznej ścieżce renderowania. Drugi to wykonywanie kodu na głównym wątku, kiedy przeglądarka powinna już malować stronę albo reagować na użytkownika.
W praktyce najbardziej szkodzą:
- skrypty w
<head>bezdefer, - duże paczki JS ładowane globalnie na każdej podstronie,
- biblioteki używane dla jednego małego efektu,
- trackery marketingowe uruchamiane przed treścią,
- skrypty czatu, map, opinii i social mediów ładowane od razu,
- stare paczki z kodem dla przeglądarek, których użytkownicy strony już prawie nie używają,
- kod inicjalizujący komponenty, których nie ma na danej podstronie.
Nie zaczynałbym od mikrooptymalizacji typu skrócenie nazw zmiennych czy ręczne poprawianie pojedynczych funkcji. Największy efekt zwykle daje zmiana kolejności ładowania i usunięcie kodu z krytycznej ścieżki.
Najpierw napraw skrypty krytyczne dla startu strony:
<script src="/js/app.js" defer></script>
Atrybut defer sprawia, że skrypt pobiera się równolegle z parsowaniem HTML, ale wykonuje dopiero po przetworzeniu dokumentu. To dobry wybór dla skryptów, które potrzebują DOM i mają zachować kolejność wykonania.
Dla niezależnych skryptów zewnętrznych można użyć async:
<script async src="https://example.com/tracker.js"></script>
Tu trzeba uważać. async wykonuje skrypt tak szybko, jak będzie dostępny, więc kolejność nie jest gwarantowana. To pasuje do analityki albo niezależnych pikseli, ale nie do kodu, który zależy od wcześniejszego załadowania biblioteki.
Jeżeli projekt używa modułów, warto pamiętać, że:
<script type="module" src="/js/main.js"></script>
skrypty modułowe są domyślnie odroczone. Nie oznacza to jednak, że można bezkarnie wysłać użytkownikowi ogromny bundle. Moduł załadowany później nadal może zająć główny wątek i pogorszyć interakcje.
Priorytety naprawy ustawiałbym tak:
- Usuń albo odrocz skrypty blokujące pierwszy ekran
Jeżeli Lighthouse pokazuje konkretny URL jako blokujący renderowanie, to jest pierwsze miejsce do sprawdzenia. Nie zgaduj, tylko porównaj waterfall przed i po zmianie. - Podziel JavaScript na mniejsze części
Kod koszyka nie musi ładować się na wpisie blogowym. Kod formularza rezerwacji nie musi być na stronie głównej, jeśli formularz jest dopiero po kliknięciu. To jest miejsce na code splitting i ładowanie warunkowe. - Usuń nieużywany JavaScript
W wielu serwisach 40–70% kodu pobranego przy pierwszym wejściu nie jest potrzebne do wyrenderowania pierwszego widoku. Nie zawsze da się usunąć wszystko, ale da się ograniczyć startową paczkę. - Opóźnij skrypty firm trzecich
Czat, mapa, widget opinii, pixel reklamowy i narzędzia heatmap nie powinny wygrywać z nagłówkiem, tekstem i głównym obrazem. Część z nich można ładować po zgodzie użytkownika, po interakcji, po kilku sekundach albo dopiero na podstronach, gdzie mają sens. - Zostaw w spokoju skrypty naprawdę krytyczne
Nie wszystko trzeba odraczać. Jeżeli skrypt odpowiada za poprawne wyrenderowanie ceny, dostępności produktu, walidację koszyka albo zabezpieczenie procesu płatności, agresywne przesuwanie go „na później” może zepsuć funkcję ważniejszą niż wynik w teście.
Granica jest prosta: wydajność nie może niszczyć działania strony. Jeżeli po optymalizacji menu miga, formularz nie działa, zgody cookies ładują się za późno albo cena produktu pojawia się po kilku sekundach, to nie jest optymalizacja, tylko przeniesienie problemu w inne miejsce.
Co robić, a czego nie robić przy optymalizacji JavaScriptu
Najbezpieczniejsza procedura wygląda tak: pomiar, zmiana, ponowny pomiar, kontrola błędów. Jedna zmiana naraz. Przy JavaScripcie masowe „przerzucenie wszystkiego do stopki” często kończy się awarią slidera, formularza albo koszyka.
Zacznij od listy skryptów. W DevTools albo w raporcie Lighthouse wypisz:
- adres pliku,
- rozmiar transferu,
- rozmiar po rozpakowaniu,
- czas pobierania,
- czas wykonania,
- właściciela skryptu: własny kod, motyw, wtyczka, reklama, analityka, zewnętrzny widget,
- podstrony, na których jest naprawdę potrzebny.
Potem podejmij decyzję dla każdego skryptu:
- zostawić w krytycznej ścieżce, jeśli bez niego pierwszy widok jest błędny,
- dodać
defer, jeśli skrypt potrzebuje DOM i kolejności wykonania, - dodać
async, jeśli skrypt jest niezależny, - ładować warunkowo, jeśli jest potrzebny tylko na wybranych podstronach,
- ładować po interakcji, jeśli dotyczy elementu otwieranego kliknięciem,
- usunąć, jeśli nie ma właściciela, celu albo mierzalnego zastosowania.
Przykład ładowania skryptu dopiero po kliknięciu:
<button id="load-map">Pokaż mapę</button>
<script>
document.getElementById('load-map').addEventListener('click', function () {
const script = document.createElement('script');
script.src = 'https://maps.example.com/widget.js';
script.async = true;
document.body.appendChild(script);
});
</script>
To ma sens przy mapach, czatach, widgetach opinii i osadzonych narzędziach, które nie są potrzebne od razu. Nie stosowałbym tego do głównego menu na mobile, jeżeli użytkownik może chcieć otworzyć je natychmiast po wejściu.
Czego nie robić?
- Nie dodawaj
asyncdo wszystkiego
Skrypty zależne od siebie mogą wykonać się w złej kolejności. Efekt: błędy w konsoli i losowo niedziałające funkcje. - Nie usuwaj skryptów bez sprawdzenia źródła
Plik o brzydkiej nazwie może obsługiwać płatności, zgodę cookies albo dynamiczne ceny. - Nie patrz tylko na wynik Lighthouse
Wynik 95/100 nie gwarantuje, że użytkownicy mają dobrą stronę. Test laboratoryjny pomaga, ale decyzje warto potwierdzać danymi z realnych wizyt. - Nie ładuj całej aplikacji na każdej podstronie
To częsty błąd w serwisach zbudowanych na ciężkich motywach lub SPA. Blog, landing page i koszyk mają inne potrzeby. - Nie opóźniaj skryptów odpowiedzialnych za zgodność prawną bez konsultacji
Baner zgód, zarządzanie consent mode czy skrypty prywatności muszą działać zgodnie z wdrożonym procesem. Tu nie wystarczy „żeby było szybciej”.
Najbardziej praktyczny plan naprawy:
- Uruchom PageSpeed Insights dla strony głównej i 2–3 ważnych podstron.
- W Chrome DevTools sprawdź waterfall i główny wątek.
- Oznacz skrypty jako: krytyczne, potrzebne później, zbędne, nieznane.
- Dodaj
deferdo własnych skryptów, które mogą poczekać na parsowanie HTML. - Dla niezależnych narzędzi zewnętrznych testuj
asyncalbo ładowanie po interakcji. - Usuń JS ładowany globalnie, jeśli dotyczy tylko jednej sekcji lub podstrony.
- Po każdej zmianie sprawdź konsolę błędów, formularze, menu, koszyk, wyszukiwarkę i ścieżkę zakupu.
- Porównaj LCP, INP, TBT i realne działanie strony przed i po zmianie.
Najpierw usuwaj blokady pierwszego renderowania. Dopiero potem walcz o mniejsze paczki, tree shaking, dynamiczne importy i porządki w zależnościach. Odwrotna kolejność często daje ładny refaktor, ale słaby efekt dla użytkownika.
FAQ: najczęstsze pytania o skrypty JavaScript blokujące ładowanie strony
Czy każdy JavaScript w <head> jest zły?
Nie. Problemem jest skrypt, który blokuje parsowanie HTML i nie jest potrzebny do pierwszego widoku. Czasem kod w <head> jest uzasadniony, ale powinien mieć konkretny powód.
Czy wystarczy dodać defer do wszystkich skryptów?
Nie zawsze. defer jest bezpieczny głównie dla skryptów, które mogą wykonać się po sparsowaniu dokumentu i zachowują kolejność. Skrypty zależne od wcześniejszego kodu trzeba testować po zmianie.
Kiedy używać async?
Przy skryptach niezależnych, które nie muszą czekać na inne pliki i od których inne pliki nie zależą. Typowy przykład to część narzędzi analitycznych. Nie jest to dobry wybór dla kodu aplikacji wymagającego przewidywalnej kolejności.
Czy skrypty firm trzecich naprawdę tak spowalniają stronę?
Często tak. Widget czatu, mapa, remarketing, heatmapy i zewnętrzne osadzenia potrafią dodać wiele żądań oraz zająć główny wątek. Najlepiej ładować je tam, gdzie są potrzebne, a nie globalnie.
Czy optymalizacja JavaScriptu zawsze poprawi pozycje w Google?
Nie da się tego zagwarantować. Może poprawić warunki techniczne strony, Core Web Vitals i doświadczenie użytkownika, ale ranking zależy też od treści, linków, intencji zapytania, konkurencji i jakości całego serwisu.
Co sprawdzić jako pierwsze, jeśli strona ładuje się wolno?
Najpierw raport Lighthouse i zakładkę Performance w DevTools. Jeżeli widać skrypty blokujące renderowanie lub długie zadania na głównym wątku, zacznij od odroczenia, ograniczenia albo usunięcia tych konkretnych plików.
Czy w WordPressie problem zwykle powodują wtyczki?
Bardzo często tak, ale nie tylko. Winny bywa motyw, page builder, globalnie ładowane biblioteki, źle wdrożona analityka albo kilka małych wtyczek, które razem generują ciężki start strony.
Od czego zacząć naprawę bez ryzyka zepsucia strony?
Od dodania defer do własnych, niekrytycznych skryptów i wyłączenia globalnego ładowania kodu na podstronach, które go nie używają. Po każdej zmianie trzeba sprawdzić konsolę błędów oraz najważniejsze funkcje strony.
Najlepszy pierwszy krok to nie „przyspieszyć wszystko”, tylko wskazać jeden skrypt, który blokuje pierwszy ekran, i usunąć go z krytycznej ścieżki. Potem kolejny. Takie podejście jest mniej efektowne niż wielka przebudowa, ale zwykle daje szybszy i bezpieczniejszy rezultat.
Więcej informacji na stronie: https://szymonsarnecki.pl
