|
|||||||||||||
|
|
||||||||
Aleksandar Vacić | |||
DOM i brzina učitavanja |
|||
Proces izvršavanja JavaScript funkcija na Internet stranici može da potraje, ali postoje načini da ubrzate iscrtavanje vašeg Web čeda... |
Završavate CMS Web aplikaciju na kojoj radite već duže vreme, sve funkcionalnosti su isprogramirane i vreme je za optimizaciju koda. Svaki ekran aplikacije, odmah nakon učitavanja stranice, inicijalizuje određene promene izvršavanjem jedne ili više JavaScript funkcija. Dok se one ne izvrše, nijedan drugi skript na strani ne radi; namerno ste tako postavili da neka funkcija ne bi bila pozvana pre nego što se inicijalizuje kontekst u kome se izvršava. Jedan od načina testiranja jeste učitavanje većeg broja slika u tekst dokumenta koji će biti objavljen putem CMS-a. Odjednom, shvatate da se nešto čudno dešava – skriptovi se jako dugo ne izvršavaju. Gledate u status bar, browser ispisuje da učitava 12/17 slika. „Ali kakve veze imaju slike, sam dokument se već učitao, šta čekaš?“ Bez obzira na viku i galamu, browser ne izvršava ništa dok se ne okonča prenos i poslednjeg bajta svih referenciranih objekata na strani. Zašto? Jer ste koristili window.onload za početak inicijalizacije. U ovom članku ćemo vam prikazati bolje rešenje. Cilj pred nama...Problem nije nov i postojao je praktično od momenta kada se JavaScript prvi put pojavio u Netscape Navigator-u, tj. od momenta kada su dodati event handler-i. Bez obzira da li se radilo o iritirajućim pozdravnim dijalozima ili o smislenoj upotrebi opisanoj u prethodnom scenariju, autori stranica su želeli da neke od svojih skriptova izvrše što je moguće pre. Svojevremeno je, upravo u te svrhe, u HTML 4.0 standard (a kasnije i u DOM1) elementu script dodat atribut defer, čija je vrednost mogla biti true ili false. Kada stavite true, browser neće parsirati skript u trenutku kada ga učita, već tek kada završi sa učitavanjem kompletne stranice. Šta vam to donosi? Pogledajte sliku 1, koja pokazuje kako browser (u ovom slučaju FireFox) tokom određenog vremena učitava elemente stranice. Možete videti da, u momentu kada krene da učitava bilo koji JavaScript fajl, sve ostalo čeka. I čekaće sve dok se skript ne prenese, parsira i dok se ne izvrše sve operacije koje su u samom fajlu napisane tako da se moraju odmah izvršiti. I tako sa svakim skript fajlom posebno. Atribut defer omogućava uštedu na parsiranju i izvršavanju u momentu učitavanja.
No, ovo nije dovoljno ubrzanje i ne rešava problem binarnog sadržaja strane, npr. prethodno spomenutih slika. Slika 2, koja prikazuje vreme učitavanja (na 256/64 kbps ADSL vezi) delova jedne opsežne stranice, odlično ilustruje naš cilj. Crveni graničnik (skroz desno) obeležava trenutak kada se dešava window.onload. Čitav sadržaj stranice je u tom momentu iscrtan i browser tada ispisuje „Done“ u statusnoj liniji. Žuti graničnik ukazuje na tačku kada su učitani CSS i Javascript fajlovi referencirani u HEAD delu stranice, tj. momenat kada browser kreće sa iscrtavanjem stranice. Drugim rečima, od tog trenutka korisnik umesto prazne strane vidi prvi sadržaj koji pristiže. Narandžasti graničnik obeležava (još raniji) trenutak kada su učitani esencijalni skriptovi na strani. Svi skriptovi između narandžastog i žutog graničnika se ne izvršavaju momentalno, već se tu nalaze funkcije koje se koriste nakon završetka učitavanja. Ovo su skriptovi nad kojima bi valjalo primeniti defer. Plavi graničnik ukazuje na momenat kada je Web site učitao HTML dokument. To je Web „nirvana“ koju je praktično nemoguće dostići – stranica počinje da se iscrtava pred korisnikom istog časa. Zvuči divno, zar ne – stranica na koju se čeka pola sekunde. Međutim, to bi značilo da se stranica iscrtava bez stilova, kao suvi tekst. Zato treba stremiti ka trenutku koji je označen zelenim graničnikom – kada su učitani svi stilovi i dokument počinje da se iscrtava u skladu sa stilovima. Podsećamo na troslojnu arhitekturu stranice: podaci, prezentacija, ponašanje. Ako sve skriptove premestite u treći sloj, gde im je i mesto, onda imate šansu da vreme učitavanja stranice spustite na zelenu tačku. Da vidimo kako. ...i kako do njegaPretpostavka je da ste sve skriptove napisali tako da se inicijalizuju nakon iscrtavanja stranice – to je osnova bez koje ne vredi ići dalje. Tehnika koja sledi je krajnje neuobičajena, tj. potpuno suprotna onome što većina knjiga i Web sajtova savetuje. Naime, obično se savetuje da skriptove učitavate unutar HEAD dela stranice, da bi oni bili keširani. Sasvim sam siguran da u nekom od ranijih tekstova u našem časopisu stoji takav savet. Uzrok tome su neki browser-i, pre svega Internet Explorer, koji su imali stari bag da ne keširaju skriptove koji su referencirani iz BODY dela dokumenta. Na sreću, situacija se izmenila i sada svi browser-i keširaju skriptove odakle god da ih pozivate. Posledica učitavanja skriptova u HEAD delu je žuta tačka – dok browser stigne do BODY dela, mora da sačeka da se svi skriptovi prenesu. To ume da potraje na dinamičkim sajtovima, a pogotovo u Web aplikacijama koje najčešće imaju čitavu gomilu skriptova koji kontrolišu stranicu. U situaciji kada su svi skriptovi odvojeni u treći sloj strukture, zašto ih ne bismo pomerili na kraj BODY dela? Pogledajte opet sliku 2 i liniju u kojoj se učitava play.js, blizu dna. Tu se lepo vidi da sav sadržaj koji u dokumentu sledi iza njega čeka na učitavanje skripta. Sam browser takođe čeka na izvršavanje skripta pre nego što kompletira Document Object Model stranice. Ako učitavanje naših skriptova smestimo na sam kraj BODY dela i pri tom ih učitavamo sa defer atributom, onda će browser kompletirati DOM pre nego se sav binarni sadržaj prenese. To je ključni momenat – sada ostaje da se inicijalizacioni skriptovi napišu tako da se umesto na window.onload izvršavaju na... DOM.onloadNo, to je lakše reći nego učiniti i sve donedavno nije postojalo rešenje koje bi funkcionisalo u svim aktuelnim browser-ima. Nekoliko Web developera je uložilo dosta vremena i truda da pronađu rešenje za sve browser-e i zaslužuju i više od spominjanja imena: Dean Edwards, John Resig i Matthias Miller. Pretpostavimo da se inicijalizaciona funkcija zove init(). Najlakši posao imamo u modernim browser-ima koji imaju punu implementaciju DOM2 Event modela, konkretno DOMContentLoaded događaj. To su trenutno Mozilla browser-i (Firefox, Camino) i Opera 9.02 i za njih je dovoljna samo 1 linija koda, na slici 3. Internet Explorer je mnogo tvrđi orah i zahteva kod sa slike 4. Čudni redovi na početku i na kraju predstavljaju tzv. kondicionalno kompajliranje (više o tome na stranici: msdn.microsoft.com/library/en-us/script56/html/js56jsconconditionalcompilation.asp ); možete ih posmatrati kao JavaScript ekvivalent uslovnih HTML komentara. Samo IE će izvršiti kod između njih, ostali browser-i će ih smatrati za skript komentar. Zapravo se simulira učitavanje nepostojećeg .js fajla, zatim se proverava da li se „učitao“ i onda se taj događaj iskoristi za izvršenje funkcije koja nas zanima. Liči na vudu magiju, ali radi. Slična akrobacija je potrebna i za Safari, default browser na Mac OS X platformi (slika 5). Tu se kontinuirano proverava postavljanje flaga document.readyState na loaded ili complete. Kada se to desi, izvrši se funkcija. Naravno, Safari je browser koji se razvija i ne sumnjam da će uskoro i on koristiti kod sa slike 3. U praksi, nekoliko ljudi je napisalo skript koji objedinjuje ova tri fragmenta u jedan fajl, a meni se najviše dopada rešenje koje je smislio Rob Cherny na adresi www.cherny.com/webdev/27/domloaded-updated-again . To rešenje se koristi i u primerima na pratećem disku. Sada vama preostaje da se zabavljate sređujući svoje skriptove i zatim uživate u brzini otvaranja sajtova. Prilozi:
pc129dom.zip (1,77 kB) |
|