December 5, 2025
De ce async și defer nu sunt interschimbabile și cum alegi atributele corect?

M-am lovit de destule ori de developeri care aruncă un async sau defer pe scripturile lor de JavaScript fără să priceapă exact ce face fiecare. Și îi înțeleg, sincer. La prima vedere par să rezolve aceeași treabă. Amândouă îți promit pagini care se încarcă mai repede, utilizatori care nu mai stau să aștepte, totul mai fluid. Doar că realitatea arată altfel.

Cele două atribute funcționează complet diferit, și dacă le confunzi sau le pui la întâmplare, riști să îți strici pagina mai tare decât dacă nu încercai deloc să optimizezi.

Hai să vedem care e treaba de fapt. Când pui un script normal în HTML, fără nimic special pe el, browser-ul face ceva care poate părea ciudat. Se oprește din ce făcea. Adică el parcurge liniștit HTML-ul tău, construiește pagina bucată cu bucată, totul merge bine, și deodată dă peste un tag de script. Ce face? Se blochează complet.

Nu mai citește nimic din HTML. Descarcă scriptul ăla, îl rulează, și abia după aia își vede mai departe de treabă. Practic utilizatorul tău se uită la un ecran alb sau jumătate încărcat, așteptând ca scriptul să termine.

De ce browser-ul se comportă așa

Are și el logica lui, recunosc. JavaScript-ul poate să schimbe complet pagina prin chestii precum document.write sau prin tot felul de manipulări ale DOM-ului. Deci browser-ul trebuie să fie sigur că știe exact ce conținut afișează înainte să meargă mai departe. Dacă ar continua să construiască pagina în paralel, iar apoi scriptul ar veni să modifice totul, ar fi un haos de nedescris.

Problema e că asta oferă o experiență proastă utilizatorului. Mai ales când scriptul e voluminos sau serverul răspunde greu sau conexiunea e slabă. Mi-am văzut suficiente site-uri unde ai impresia că nu se încarcă absolut nimic, deși în realitate HTML-ul e deja acolo, doar că așteaptă după un script care blocheaza redarea site-ului. E frustrant pentru toată lumea implicată.

Ce face async de fapt

Aici apare async-ul. Când îl pui pe un script, practic spui browser-ului ceva de genul: descarcă-l în paralel, pe fundal, în timp ce tu continui treaba cu HTML-ul. Sună minunat, nu? Pagina se construiește, scriptul se descarcă simultan, toată lumea fericită.

Partea interesantă vine exact la execuție. Când scriptul s-a descărcat complet, browser-ul se oprește din ce făcea și îl execută imediat. Nu așteaptă să termine HTML-ul, nu se gândește dacă e un moment potrivit, pur și simplu rulează scriptul chiar atunci. Asta înseamnă că nu ai nicio garanție când exact se va executa codul tău.

Îmi amintesc un proiect unde aveam trei scripturi marcate cu async, și ordinea în care se executau era de fiecare dată alta. Dependea de viteza de descărcare, de cât de mare era fiecare fișier, de cache. Complet imprevizibil. Pentru unele cazuri asta merge, chiar e avantajos. Pentru altele e o catastrofă.

Cum lucrează defer și de ce contează diferența

Defer e gândit altfel de la bun început. Când pui defer pe un script, browser-ul îl descarcă și el în paralel, exact ca la async. Deci tot nu blochează procesarea HTML-ului, ceea ce e foarte bine. Dar diferența esențială apare la momentul execuției.

Un script cu defer are răbdare. Nu se execută imediat după descărcare. Așteaptă până când browser-ul a terminat complet de procesat tot HTML-ul, până când întreaga structură a paginii e construită. Abia atunci, chiar înainte de evenimentul DOMContentLoaded, scripturile cu defer se execută în ordinea exactă în care au apărut în HTML.

Asta e un aspect imens pe care mulți îl trec cu vederea. Cu defer, ordinea nu numai că contează, dar e și garantată. Dacă ai script1.js cu defer, apoi script2.js tot cu defer, poți fi absolut sigur că script1 se execută înaintea lui script2. Întotdeauna. Asta face defer incredibil de util când ai scripturi care depind unele de altele.

Situații concrete în care contează

Să ne gândim la exemple reale. Ai un script de analytics, fie că e Google Analytics sau altceva similar. Vrei să încarce cât mai repede posibil, dar nu îți pasă exact când se execută și nu depinde de alte lucruri din pagină. Async e perfect pentru asta. Se descarcă undeva pe fundal, se execută când e gata, nu încurcă nimic.

Dar dacă ai jQuery ca dependență și apoi un script care folosește jQuery? Aici async devine problematic, chiar riscant. Poate se descarcă jQuery mai repede, se execută primul, totul ok. Sau poate scriptul tău se descarcă primul, încearcă să folosească jQuery care încă nu există, și primești erori ciudate în consolă. Cu defer, toată problema asta dispare. jQuery se încarcă, apoi scriptul tău, în ordinea corectă, fără surprize.

Am văzut developeri care pun async peste tot pentru că “merge mai rapid”, fără să înțeleagă că viteza nu înseamnă mare lucru dacă aplicația nu funcționează cum trebuie. Viteza trebuie echilibrată cu fiabilitatea, altfel ajungi cu o mașină rapidă care se defectează la fiecare colț de stradă.

Când n-ar trebui să folosești niciunul

Există momente când nici async, nici defer nu sunt alegerea potrivită. Dacă scriptul tău absolut trebuie să se execute într-un punct foarte specific din timpul procesării HTML-ului, dacă folosește document.write sau dacă alte scripturi sincrone depind de el, atunci e mai sigur să nu pui niciun atribut pe el.

Da, pagina va încărca mai greu. Dar va funcționa. Și uneori funcționalitatea e mai importantă decât viteza pură. E ca și cum ai alege între o mașină rapidă care te lasă baltă constant și una mai lentă dar pe care te poți baza. Depinde ce îți dorești mai mult.

Cum decizi în practică

Gândește-te la scriptul tău ca la o persoană care vine la o petrecere, poate părea aiurea comparația dar merge. Async e tipul care ajunge când poate, face ce are de făcut imediat, poate chiar întrerupe alte conversații pe parcurs. Defer e cel care așteaptă politicos până când toată lumea e așezată la masă, apoi participă la discuție în ordinea firească.

Pentru scripturi de tracking, reclame, widget-uri sociale, toate lucrurile care nu afectează funcționalitatea principală a paginii, async e alegerea ta. Se încarcă independent, se execută când sunt gata, nu stau în calea experienței utilizatorului.

Pentru framework-uri, librării, orice cod care manipulează DOM-ul sau depinde de structura completă a paginii, defer e calea de urmat. Vrei să fii sigur că totul e pregătit înainte să intervii cu modificări. Are sens, nu?

Și pentru scripturile critice care trebuie să se execute exact când le întâlnește browser-ul în document, fără atribute e varianta cea mai sigură. Nu toate optimizările se potrivesc pentru toate situațiile, și asta e ok.

Testarea contează enorm

N-am să mint, deciziile astea nu sunt întotdeauna evidente de la început. Am petrecut ore întregi debuguind probleme care țineau doar de ordinea de execuție a scripturilor. De aia testarea e esențială, nu opțională. Deschide DevTools, privește la tab-ul Network, vezi cum se încarcă scripturile, când se execută fiecare.

Chrome îți arată exact ce blochează și ce nu. Poți vedea waterfall-ul de încărcări, poți înțelege dependențele dintre resurse. Firefox are instrumente similare, la fel de bune. Folosește-le constant. Nu ghici niciodată, măsoară și verifică.

Și foarte important, testează pe conexiuni lente. Throttle bandwidth-ul în DevTools la 3G sau chiar mai jos. Acolo vezi cu adevărat dacă deciziile tale funcționează în realitate. Pe o conexiune rapidă de birou, multe probleme se ascund frumos sub preș. Pe una lentă, toate ies la suprafață și te lovesc direct.

Am învățat asta dur când am lansat un site care părea perfect pe conexiunea mea de la birou, dar era practic inutilizabil pe mobil cu date mobile. Async-ul pe care îl pusesem cu atâta încredere făcea scripturile să se execute într-o ordine complet haotică care strica funcționalitatea principală. Am trecut totul pe defer și problema s-a rezolvat instant. Lecție învățată, zic eu.

Async și defer nu sunt interschimbabile tocmai pentru că rezolvă probleme diferite prin metode diferite. Unul îți oferă viteză maximă fără garanții de ordine. Celălalt îți dă viteză cu predictibilitate completă.

Alegerea dintre ele depinde de ce face scriptul tău, de ce are nevoie, de ce depinde, și de cât de important e momentul exact al execuției. Pune-ți aceste întrebări pentru fiecare script în parte și vei ști exact ce atribut să folosești. E mai simplu decât pare odată ce înțelegi mecanismul de bază.