Oto, co się dzieje, gdy przeglądarka ładuje witrynę z <script>
tagiem:
- Pobierz stronę HTML (np. Index.html)
- Rozpocznij analizowanie kodu HTML
- Analizator składni napotka
<script>
znacznik odwołujący się do zewnętrznego pliku skryptu.
- Przeglądarka żąda pliku skryptu. W międzyczasie analizator blokuje i przestaje analizować inny kod HTML na stronie.
- Po pewnym czasie skrypt jest pobierany, a następnie wykonywany.
- Analizator składni kontynuuje analizowanie reszty dokumentu HTML.
Krok # 4 powoduje złe wrażenia użytkownika. Twoja witryna zasadniczo przestaje się ładować, dopóki nie pobierzesz wszystkich skryptów. Jeśli coś nienawidzi użytkowników, czeka na załadowanie strony internetowej.
Dlaczego tak się dzieje?
Każdy skrypt może wstawiać własny kod HTML za pośrednictwem document.write()
lub innych manipulacji DOM. Oznacza to, że analizator składni musi poczekać, aż skrypt zostanie pobrany i wykonany, aby mógł bezpiecznie przeanalizować resztę dokumentu. W końcu skrypt mógł wstawić własny dokument HTML do dokumentu.
Jednak większość programistów JavaScript nie manipuluje już DOM podczas ładowania dokumentu. Zamiast tego czekają na załadowanie dokumentu, zanim go zmodyfikują. Na przykład:
<!-- index.html -->
<html>
<head>
<title>My Page</title>
<script src="my-script.js"></script>
</head>
<body>
<div id="user-greeting">Welcome back, user</div>
</body>
</html>
JavaScript:
// my-script.js
document.addEventListener("DOMContentLoaded", function() {
// this function runs when the DOM is ready, i.e. when the document has been parsed
document.getElementById("user-greeting").textContent = "Welcome back, Bart";
});
Ponieważ twoja przeglądarka nie wie, że my-script.js nie zmodyfikuje dokumentu, dopóki nie zostanie pobrany i wykonany, analizator przestaje analizować.
Zalecenia przestarzałe
Stare podejście do rozwiązania tego problemu polegało na umieszczaniu <script>
tagów na spodzie twojego <body>
, ponieważ zapewnia to, że parser nie zostanie zablokowany do samego końca.
Takie podejście ma swój własny problem: przeglądarka nie może rozpocząć pobierania skryptów, dopóki cały dokument nie zostanie przeanalizowany. W przypadku większych witryn z dużymi skryptami i arkuszami stylów możliwość jak najszybszego pobrania skryptu jest bardzo ważna dla wydajności. Jeśli witryna nie załaduje się w ciągu 2 sekund, ludzie przejdą do innej witryny.
W optymalnym rozwiązaniu przeglądarka zacznie pobierać skrypty tak szybko, jak to możliwe, jednocześnie analizując resztę dokumentu.
Nowoczesne podejście
Obecnie przeglądarki obsługują skrypty async
i defer
atrybuty. Te atrybuty mówią przeglądarce, że parsowanie skryptów jest bezpieczne.
asynchronizacja
<script src="path/to/script1.js" async></script>
<script src="path/to/script2.js" async></script>
Skrypty z atrybutem asynchronicznym są wykonywane asynchronicznie. Oznacza to, że skrypt jest wykonywany natychmiast po pobraniu, bez blokowania przeglądarki w międzyczasie.
Oznacza to, że możliwe jest pobranie i wykonanie skryptu 2 przed skryptem 1.
Według http://caniuse.com/#feat=script-async , 97,78% wszystkich przeglądarek obsługuje to.
odraczać
<script src="path/to/script1.js" defer></script>
<script src="path/to/script2.js" defer></script>
Skrypty z atrybutem odroczenia są wykonywane w kolejności (tj. Najpierw skrypt 1, a następnie skrypt 2). To również nie blokuje przeglądarki.
W przeciwieństwie do skryptów asynchronicznych, odroczone skrypty są wykonywane dopiero po załadowaniu całego dokumentu.
Według http://caniuse.com/#feat=script-defer 97,79% wszystkich przeglądarek obsługuje to. 98,06% popiera to co najmniej częściowo.
Ważna uwaga na temat kompatybilności przeglądarki: w niektórych przypadkach IE <= 9 może wykonywać odroczone skrypty w kolejności. Jeśli potrzebujesz obsługi tych przeglądarek, przeczytaj to najpierw!
Wniosek
Obecnym stanem techniki jest umieszczanie skryptów w <head>
tagu i używanie atrybutów async
lub defer
. Pozwala to na szybkie pobieranie skryptów bez blokowania przeglądarki.
Dobrą rzeczą jest to, że witryna powinna nadal poprawnie ładować się w 2% przeglądarek, które nie obsługują tych atrybutów, przy jednoczesnym przyspieszeniu pozostałych 98%.