Az async és defer attribútumok

Modern weboldalaknál a JS fájlok sokszor nagyobbak és bonyolultabbak, mint maga a HTML: a letöltési méretük nagyobb, és a feldolgozási idejük is hosszabb. Ennek a következményeiről, és a felmerülő problémák elkerüléséről lesz most szó.

Amikor a böngésző <script> taggel találkozik, akkor szünetelteti a dokumentum feldolgozását, letölti a JS fájlt, futtatja, és csak utána folytathatja a dokumentum betöltését.

Ez kétféle problémát okozhat:

  1. A JS kód nem “látja” azokat az elemeket, amik a <script> tag után jönnek a HTML-ben, úgyhogy azokat csak akkor tudjuk manipulálni, ha valamilyen késleltető mechanizmust alkalmazunk a kódban.
  2. Ha túl “bonyolult” JS kód van a dokumentum elejére beillesztve, az hosszú időre blokkolhatja a dokumentum betöltését.

Ezekre a problémákra megoldás lehet a <script> elem beillesztése a dokumentum aljára, valahova a záró </body> elé. De ez nem egy tökéletes megoldás: a böngésző csak a teljes HTML dokumentum után fogja észlelni és elkezdeni letölteni a <script> tag-et. Nagyméretű dokumentumok és/vagy lassú internetkapcsolat esetén ez jókora késést okozhat a script elindításában. Gyors kapcsolat esetén az ilyet általában észre sem lehet venni, de érdemes észben tartani, hogy a gyors internetelérés lehetősége nem mindenkinek adatik meg.

Szerencsére létezik két speciális attribútum, amiket hozzáadhatunk a <script> tag-hez, és megoldják a fenti problémákat:

Az async attribútum

Az async attribútum tudatja a böngészővel, hogy az adott JS kód a dokumentumtól teljesen függetlenül betölthető és futtatható:

  • Az asnyc script nem blokkolja a HTML további feldolgozását. A böngésző elkezdi letölteni a fájlt, de közben tovább halad a HTML feldolgozása.
  • Más scriptek nem lesznek késleltetve, hogy az async script után fussanak, és az async-ek sem lesznek késleltetve semmilyen más script miatt, tehát a futtatási sorrendjük más lehet, mint a forrásban megadott.
  • Az async scriptek a DOMContentLoaded eseménytől is függetlenek: a load esemény bekövetkezhet az async script futtatása előtt és után is. Ha előtte történik, akkor a script-ben lévő callback lehet, hogy nem fog működni.

Magyarán, az async scriptek a háttérben betöltenek és aztán lefutnak, amint készen állnak.

Az async attribútum többek közt alkalmas a külső scriptek (számlálók, statisztikák, reklámok, stb.) beágyazására, mivel ezek általában függetlenek a saját website scriptjeitől. Például az Analytics követőkódot szokták így behívni:

<script async src="https://google-analytics.com/analytics.js"></script>

A defer attribútum

A defer attribútummal azt mondjuk a böngészőnek, hogy kezdje el letölteni a fájlt, de ne várja meg a betöltését és a futtatását. Helyette a script a háttérben letöltődik, majd a teljes dokumentum-szerkezet felépítése után lesz futtatva a script.

A defer attribútumos scriptek a forrás által meghatározott sorrendben lesznek futtatva, ugyanúgy, mint az attribútum nélküli, sima scriptek. Ez fontos részlet, ha függőségi viszony van több script között.

Tehát, pontokba szedve:

  • A defer attribútummal ellátott scriptek sosem blokkolják a dokumentum betöltését.
  • A defer attribútummal ellátott scriptek csak a dokumentum betöltése után lesznek futtatva (de még a DOMContentLoaded esemény előtt, tehát használhatjuk azt a kódban).
  • A defer attribútummal ellátott scriptek a megadott sorrendben lesznek futtatva.

Alternatíva: a dinamikusan betöltött scriptek

Létezik egy másik módja a script fájlok betöltésének: a fájlok Javascriptben történő dinamikus betöltése. Például:

let script = document.createElement('script');
script.src = "/script/egyeni-script.js";
document.body.append(script);

A fájl betöltése akkor kezdődik meg, amikor az elemet hozzáadjuk a dokumentumhoz (az utolsó sor a fenti kódban), és ez a módszer az async scriptekhez hasonlóan fog működni: nem várnak más scriptre, és lefutnak, amint betöltődtek. Ezt a működési módot megváltoztathatjuk a script.async tulajdonság false értékre állításával:

let script   = document.createElement('script');
script.src   = "/script/egyeni-script.js";
script.async = false;
document.body.append(script);

Így a script a dokumentum betöltése után lesz futtatva, tehát úgy fog viselkedni, mint a defer attribútummal ellátott tag.

Async és defer WordPress-ben

WordPress használata esetén egy rövid kódrészlettel hozzá tudjuk adni az async és defer attribútumokat bármelyik WordPress által behívott JS fájlhoz: JS Fájlok Betöltése Async és Defer Attribútumokkal.

Összefoglalás

A defer-t akkor használjuk, ha a dokumentum szerkezete (a DOM) fontos a script szempontjából, vagy ha meg akarjuk őrizni a megadott futtatási sorrendet.

Az async-et pedig akkor, ha a sorrend és a HTML szerkezet nem számít, mint például számlálóknál vagy reklámoknál.

A kettőt egyszerre is hozzá lehet adni, ebben az esetben az async “erősebb”, és az lesz az irányadó a modern böngészők számára, míg régebbi böngészők, amik nem támogatják az async-et, defer-ként fogják betölteni a kódot.

Az oldal Javascript nélkül is legyen használható!

Ha defer-t vagy async-et használunk, akkor a felhasználó a script betöltése előtt már látni fogja az oldalt. Ha a JS fontos funkciókat ad hozzá, akkor annak a betöltéséig legyen fallback funkciónk, vagy jelezzük a felhasználó felé, hogy az adott elem/funkció még nem elérhető.


A Szerzőről
Piller Balázs senior webfejlesztő, SEO specialista, és a WordPress szakértője. Számos sikeres projektben vett részt vezető fejlesztőként. Az általa írt kód jelenleg több mint 1 000 000 webhelyen fut.

Vélemény, hozzászólás?

Az e-mail-címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük