Na co stránka čeká

tajemství rychlosti načítání

Když prohlížeč dostává html stránku a postupně ji vykresluje, načítá zároveň odkazované http objekty, které ve stránce nalezne. Myslím tím

Na některé objekty se přitom při načítání čeká -- to znamená, že prohlížeč zastaví vykreslování, dokud objekt nezíská celý (přesněji vzato konec jeho souboru). Uživatel zírá na prázdnou stránku a pěkně ho to štve.

Na některé jiné objekty prohlížeč nečeká a vesele pokračuje ve vykreslování stránky, objekt do stránky doplní později.

Pro stavbu rychlých stránek je důležité pochopit, na co přesně se čeká a na co ne. Hraje v tom roli spousta věcí a každý prohlížeč se chová trochu jinak (v této stránce jsou informace platné pro všechny prohlížeče, nejvíce detailů ovšem vím o Internet Exploreru).

Obecný přehled "rychlosti" objektů - Paralelní načítání stránky - Obrázky - Externí skripty - Externí styly - Iframe - Flash a podobné objekty - Zmínka o tabulkách - Poznámka o kešování

Obecný přehled "rychlosti" objektů

typ objektu čeká se na něj?
obrázek ne
obrázek na pozadí ne
externí skript ano
externí styl ano
iframe ne
flash, video a podobné objekty ne
konec html tabulky ano (v Internet Exploreru)
konec html tagu <div> ne

Z tabulky vidíte největší rizika pro rychlé vykreslování stránky. Jsou jimi externí skripty, externí styly a html tabulky. Vyplatí se ale probrat si jednotlivé věci podrobně. Napřed ale teorie načítání stránky do prohlížeče.

Paralelní načítání stránky

Stránka do prohlížeče dorazí jako odpověď na http požadavek.

Jakmile do prohlížeče dorazí začátek stránky, prohlížeč ji začne parsovat a vykreslovat. Tato fáze se pozná většinou podle toho, že se v prohlížeči úplně nahoře objeví titulek stránky (obvykle bílý v modrém proužku).

Při parsování (vyhodnocování a vykreslování) stránky vidí prohlížeč http objekty -- obrázky apod. -- a okamžitě si o ně požádá (novým http požadavkem). Zatímco pokračuje v načítání hlavní stránky, začínají do prohlížeče přicházet odpovědi s načítanými objekty (obvykle obrázky). Tak se může stahovat více objektů najednou -- říkám tomu paralelní načítání.

Při paralelním načítání tedy tečou do prohlížeče různé objekty najednou. Přitom se společně dělí o linku. Obsahuje-li pak stránka například hodně obrázků, může se načítání původní HTML stránky hodně zpomalit (což normálně nevadí, ale třeba v souvislosti s tabulkami docela ano).

Mimochodem je zajímavé, že existuje nějaký omezený počet http spojení, které je prohlížeč ochoten s konkrétním serverem najednou udržovat. Nevím, kolik to je, ale myslím, že obvykle je to kolem šesti spojení (asi se to dá někde nastavit). Máte-li na začátku stránky více načítaných objektů (zpravidla obrázky), můžete si docela zavařit, protože ten limit vyčerpají a nemusí se pak rychle dostat na nějaký důležitější čekací objekt. (S touto problematikou souvisí persistentní http spojení, ale to bych moc odbíhal.)

Načítání a vykreslování

Pokud vám to zatím nedává moc smysl, musíte si uvědomit, že existuje rozdíl mezi

Ten rozdíl někdy nemusí být vidět, ale jindy vidět je. Tato stránka se zabývá tím, aby ten rozdíl vidět nebyl. Na svých stránkách prostě nechci, aby si prohlížeč část informací sušil pro sebe (bez vykreslení) a na jiné přitom čekal.

Také je důležité zmínit, že zpomalení prohlížecího procesu není téměř nikdy podstatně ovlivněno výkonem lokálního počítače (klienta). Jinak řečeno ať máte jakoukoli šunku, pomalost zobrazování stránek je dána pouze rychlostí vaší linky, kešováním a tím, jak dobře nebo blbě autoři stránky vytvořili.

Obrázky

Obrázky jsou asi nejstarší typ načítaného objektu, a tak jsou docela v pohodě. Téměř nikdy se na ně nečeká a rychlost vykreslování stránky negativně neovlivňují (pokud jich není moc a neucpou linku nebo neobsadí limit http spojení). Stránka si pro obrázek vymezí na obrazovce místo a až obrázek dorazí, prostě ho dokreslí.

Některé obrázky se dají uložit prokládaně (interlaced), což způsobuje, že se v prohlížeči vykreslují posupně, jak přicházejí data. S problematikou této stránky to nijak nesouvisí.

I když se na obrázky načeká, pokud je obrázků na stránce moc, mohly by ucpat linku. Proto se hodí používat u nich atribut loading="lazy", tak zvané líné načítání. Dokud takové obrázky nejsou vidět, nestahují se, a začnou se stahovat, až když uživatel doroluje k jejich blízkosti.

Zadávání rozměrů

Když se obrázku zadají rozměry, stránka si na obrázek při vykreslování vyhradí přesné místo. Až obrázek dorazí, tak se na vyhrazené místo dokreslí. To je ještě jednoduché. Nezáleží přitom na tom, jestli se rozměry obrázku zadají přes html atributy width="..." height="..." nebo přes CSS styly.

Co se ale stane, pokud rozměry obrázku zadány nejsou? Zjednodušeně řečeno stránka při načítání poskakuje. Napřed vymezí nějaké malé místo a pak čeká na hlavičkovou informaci z obrázku, který stránce sdělí skutečné rozměry obrázku. Teprve pak si stránka udělá místo a obrázek vykreslí.

Zvláštní případ je, když je zadán jenom jeden rozměr. Prohlížeče se chovají různě, ale nakonec to dopadne tak, že stránka poskakuje a zadaný rozměr je akceptován.

Poskakování stránky je ještě docela v pohodě. Čtenáře to sice mate, ale aspoň už má co číst (nezírá na prázdnou stránku).

Více o obrázcích v HTML.

Jak si můžete krásně zavařit:

Dejte celou stránku do velké tabulky. Do tabulky přidejte obrázek, kterému neudáte rozměry.

Internet Explorer si napřed bude muset celou tabulku stáhnout. Kdyby tam ten obrázek nebyl, může stránku po ukončení tabulky vykreslit (pozdě, ale přece). Ale že je tam ten obrázek bez rozměrů, bude si jej muset ještě napřed stáhnout, aby zjistil, jak je velký. Teprve potom se to celé vykreslí. Pro zvýšení zpomalení je fajn do tabulky dát těch obrázků co nejvíc ("ideálně" také počítadlo, to se ještě musí vypočítat). Uživatel bude po celou tu dobu zírat na prázdnou stránku (nahoře s vypsaným titulkem) a bude ho to hrozně bavit.

Obrázek na pozadí

Na obrázek pozadí se nečeká nikdy (pokud vím). To je příjemné.

Souvisí s tím častá začátečnická chyba: datově velké tmavé obrázkové pozadí a bílé písmo stránky. Než se pozadí stáhne, je vidět bílé písmo na bílém (prázdném) pozadí. Řešení: vedle tmavého pozadí deklarujte vždy tmavou barvu (obrázek se také nemusí stáhnout vůbec).

Více o pozadí.

Externí skripty

Aby nedošlo k mýlce, mám pod pojmem externí skript na mysli něco takového:

<script type="text/javascript" src="externi-skript.js"></script>

Jakmile prohlížeč v HTML kódu najde takovýto zápis, požádá server o soubor externi-skript.js. A čeká, než soubor dorazí. Teprve až skript dorazí, provede se. Prohlížeč pokračuje ve vykreslování stránky až potom (naštěstí v načítání pokračoval celou dobu).

Většinou toto čekání pro uživatele vypadá tak, že se stránka na nějakém místě zasekne a čeká (obvykle za logem nebo záhlavím), zbytek stránky je bílý. Po pár sekundách se to najednou objeví celé.

Tento problém náhodou velmi často vypadá úplně stejně jako klasický problém tabulkového layoutu. V tabulkovém layoutu se stránka v Exploreru zasekává tam, kde začíná nějaká velká tabulka. Hodně lidí, když chtějí svoje pomalé stránky zrychlit, zruší tabulkový layout, přejdou na CSS layout, ale externí skripty tam nechají. Pak to zasekávání vidí dál (ve všech prohlížečích) a jsou z toho na prášky, protože nevědí, co se děje.

Ačkoli drobné zpomalení vyrobí každý externí skript (pokud není velmi dobře kešován), ve stránkách běžně potkávám dva typické zástupce skriptů, které tohle zpomalení způsobují v téměř kritické formě:

  1. vysouvací navigační menu
  2. bannerová reklama z cizího serveru

Javascriptová vysouvací menu mají problém v tom, že to je obvykle datově velký skript dlouhý jak Lovosice (umí totiž všechno :-/, takže asi musí být dlouhý). Navíc jsou menu často ve dvou souborech (1. soubor knihovny, 2. soubor data), což to ještě zdrží o další http požadavek (kladený sériově).

Bannerová reklama z cizích serverů vkládaná javascriptem je příšerná jednak v tom, že ty vzdálené servery bývají strašně zasekané, druhak v tom, že to je většinou totálně zprasený skript, který (pokud to zjednoduším) zavolá jiný externí skript, který zavolá jiný externí skript, který teprve vloží iframe, v němž je nějaká blikací nádhera. Navzájem to na sebe čeká (je to sériové) a může to být časově velmi dlouhé. Vrcholem ironie je fakt, že ve velké části případů server na konci anabáze poskytne prázdný kód (pro danou pozici reklamu nemá prodanou).

Proč se na javascript vlastně čeká

Možná si říkáte co je to za blbost, proč se při vykreslování nepřeskočí vyhodnocování skriptu a proč stránka nejede dál? Znám ale nejméně jeden důvod, proč se na vyhodnocení skriptů čeká -- jde o příkaz document.write(). Dá se jím do stránky (na místo, kde je skript volán) zapsat libovolný text, například neuzavřené tagy. Pro prohlížeč je tedy jednodušší skript napřed trpělivě vyhodnotit a zjistit, jestli se něco nezapisuje (aby to pak nemusel celé překreslovat).

Defer a async

Podobného problému s rychlostí si asi byli vědomi vývojáři Microsoft Internet Exploreru verze 4. Jak bylo v oné době války prohlížečů zvykem, obohatili tag <script> o tehdy nestandardní atribut defer (bez hodnoty). Atribut defer způsobuje, že se na vyhodnocení skriptu nebude čekat a stránka se načítá a vykresluje dál. Skript se provede až po donačtení stránky. Hodí se zejména na úseky skriptů, které pouze deklarují funkce pro pozdější použití. Použití defer vypadá třeba takhle:

<script src="externi-skript.js" defer></script>

Lepší je používat novější hodnotu async.

<script src="externi-skript.js" async></script>

Skript označený async na rozdíl od defer nečeká na donačtení celé stránky. Ale ani nezpůsobuje čekání, takže ho rád používám.

Řešení problému rychlosti externích skriptů

Žádná vše řešící univerzální rada neexistuje. Ale mám pár tipů:

Externí styly

Pod externím stylem mám na mysli stylopis v souboru *.css připojovaný do HTML dokumentu zápisem

<link rel="stylesheet" href="externi-styl.css" type="text/css">

Druhý možný zápis připojení externího stylového souboru je přes tag <style> a instrukci @import:

<style type="text/css">
    @import url("externi-styl.css");
</style>

Ačkoli v konečném důsledku fungují oba zápisy stejně (připojí styl), při načítání je mezi nimi v Internet Exploreru rozdíl.

Mozilla (Gecko) podle mých zkušeností na externí styl s vykreslováním čeká vždy -- jak přes link, tak na @import. Ale moc jsem to netestoval, takže mě v tomto ohledu prosím doplňte (ocením info mailem).

Opera naopak vždy načítá stránku bez čekání, podobně jako Explorer při zápisu s @import.

Čekání na styl z <link>

V jistém smyslu je situace velmi podobná externím javascriptům. Prohlížeč, který link s externím stylem potká, zastaví vykreslování stránky (zpravidla hned na začátku) a pokračuje, až když si natáhne celý styl. Protože jsou css soubory většinou malé, zdržení způsobuje zejména HTTP požadavek na css soubor. Je to určité zdržení, během kterého uživatel vidí prázdnou stránku.

Je fakt, že to zdržení nebývá velké. Nehraje to moc roli, ale je dobré o tom vědět. Na rychlém připojení většinou ani ne sekunda, záleží na velikosti souboru (akorát ten http požadavek bude stále stejně pomalý).

Možnosti zmírnění problému:

Převod stylu na interní

Existuje i jeden způsob, jak problém vyřešit (ne pouze zmírnit). Možná budete mít chuť mě za něj upálit, ale docela se mi osvědčil. Jde o použití interního stylu namísto externího. Prostě se zápis stylu do stránky zapíše mezi tagy <style> a </style>, nejlépe nějakým redakčním systémem nebo třeba PHP includem. Žádný externí soubor se nepoužívá. Ačkoli se tak zvětší celkový objem dat (přenáší se to na více stránek vícekrát), ušetří se kritické čekací http spojení na začátku dokumentu. Doporučuji to nasadit zejména u velkých serverů s jednoduchým designem a s velkým objemem http požadavků (typicky portály).

Postupné vykreslování stylu z @import

Připojení stylu pomocí formule @import se v praxi používá většinou z jiných důvodů, než je rychlost vykreslování. Nejčastějším důvodem je odříznutí velmi starých prohlížečů od stylů -- stránka se v nich objeví zcela neostylovaná, ale aspoň se to dá přečíst. Takové prohlížeče (IE4 apod.) se už naštěstí moc neobjevují. Nejvíce debilních prohlížečů se odřízne asi tímto zápisem:

<style type="text/css" media="all">
    @import "externi-styl.css";
</style>

Vedlejší efekt připojení stylu přes @import je v Internet Exploreru ten, že se stránka vykresluje postupně:

  1. Napřed se začne vypisovat text bez stylů, většinou černý text na bílém pozadí.
  2. Pak to najednou problikne (asi tak po sekundě nebo dvou, na pomalém spojení třeba po deseti sekundách) a stránka se dál už zobrazuje správně.
  3. Pokud je tam stylů přes @import připojených více, tak to poskočí vícekrát.

Zajímavá je tam ta krátká chvíle na začátku. Vzbuzuje dost kontroverzí:

Možná se vám podaří ten efekt postupného vykreslování spatřit na nějakém webu.

Závěrem na téma externích stylů bych tedy doporučil používat k připojování stylů do vlastních stránek spíše @import, protože je to v Exploreru prostě rychlejší. Já sám používám <link>, protože jsem to tak před lety začal a teď jsem líný to měnit. Jde ale jednoznačně o největší rychlostní slabinu mých stránek (kovářova kobyla). Děláte-li weby pro nějaké firmy s lamami ve vedení, připojujte raději přes <link>.

Hlavně se ale vyhněte všemu, co by mohlo css soubor zpomalit. Jsem velmi skeptický k nějakým css souborům tvořeným v PHP nebo sestavovaným třeba na základě vyhodnocování cookies. Kromě toho, že to může být pomalé, bych také čekal špatné kešování.

Různé způsoby použití stylů.

Iframe

Iframe je html tag, který do stránky do určitého prostoru načte do plovoucího rámu jinou stránku. Na stránce o iframe můžete vidět nějaké příklady. Např.:

<iframe src="externi-stranka.html" width="300" height="400"></iframe>

Podstatnou výhodou vkládání objektů přes iframe je to, že se na ně nečeká. Prohlížeč prostě vyhradí prostor a původní stránku si dál kreslí po svém. Do iframe se mezitím paralelně a nezávisle načítá externí stránka určená atributem src. Jediné, co se může přihodit, je zahlcení linky dalšími objekty, ale to je obecný problém, který asi ani nemá smysl zmiňovat.

Díky svým vlastnostem je iframe ideální metoda "zapouzdření" reklamních bannerů, které se musejí načítat ze zapráskaných cizích serverů.

Videa a podobné objekty

Je to vlastně skoro to samé, co u obrázků. Nečeká se na ně a po načtení se doplňují. Pokud se jim nezadají rozměry, mohou při načítání způsobovat poskakování stránky. Videa ještě obvykle doplňují preview obrázky, ale to s tematikou této stránky vlastně nesouvisí.

Podobně třeba hudba zadaná nějakým objektem. Spouští se až poté, co se hudební soubor stáhne celý. Vykreslování stránky to ale nezablokuje (jenom to může zpomalit načítání, protože se po lince tahá další objekt, zpravidla velký).

Zmínka o tabulkách

Špatně použité HTML tabulky mají zvláštní schopnost zastavit zobrazování stránky. Už jsem o tom psal asi stokrát (např. tady, tady), ale na tuto stránku to opět patří.

Pokud uzavřete celou stránku nebo podstatnou část stránky do jedné tabulky (tzv. tabulkový layout), čeká Internet Explorer na to, až dorazí uzavírací tag </table>. Dokud nedorazí, tabulku nevykreslí. Uživatelé čekají a koukají na prázdnou stránku.

Tabulky jsou přitom jediné HTML prvky, které podobnou lapálii způsobují (tedy pokud vím). Jinak řečeno předěláte-li design na beztabulkový pomocí ostylovaných tagů div, svoje stránky (nejen subjektivně) podstatně zrychlíte.

Poznámka o kešování

Výše v textu jsem mnohokrát zmínil, že by se externí objekty měly dobře kešovat, zvláště externí skripty a styly. Kešování je docela složité, skoro věda, ale nedávno jsem přeložil Kešovací návod pro autory webu a webmastery (obsahuje i příklady nastavování kešování). Dokonce jsem to i pochopil, a tak s tím teď můžu machrovat.

Zásadní omyl, který se mezi webmastery traduje, zní takto: "Externí styly a skripty se do prohlížeče načtou jenom jednou. Při příštím použití už se z původního serveru nestahují, takže jsou rychlé." Je to skoro celé pravda, až na to "takže jsou rychlé". To platí jenom někdy (v jedné seanci).

Je pravda, že při opětovném požadavku třeba na *.js soubor je tento soubor v keši (většinou v prohlížečové). Pokud ale přijde druhý požadavek v jiné seanci (tj. po vypnutí a zapnutí prohlížeče, záleží také na nastavení prohlížeče), musí se externí soubor zvalidovat (porovnat se serverem). Při validaci se sice většinou zjistí, že je objekt stále platný, načež se tedy žádná velká data nestahují, ale ta samotná validace zabere nějaký čas, zpravidla zhruba sekundu. A sekunda už roli hraje, protože po tu dobu vykreslování čeká.

Ve většině případů na většině hostingů se nevěnuje kešování moc pozornosti, takže objekty nemají moc vymakané http hlavičky na kešování (pokud vůbec něco takového mají). Vyplatí se ale hlavičky přenastavit. Osobně nastavuji stylům a externím skriptům (přestože je vkládám až na konec stránky) platnost asi dva měsíce. Po tu dobu se pak nemusí validovat, což způsobuje zrychlení stránek.

Ještě bych měl v souvislosti s čekáním a rychlostí přidat poznámku o komprimovaném přenosu pomocí mod_deflate či mod_gzip, ale to je příliš široké téma. Někdy příště.

 

Publikováno 6. srpna 2004, stále platné i na jaře 2017, drobná aktualizace listopad 2020

 

Reklama

www.webhosting-c4.cz, extra rychlý SSD webhosting s doménou v ceně
o tvorbě, údržbě a zlepšování internetových stránek

Návody HTML CSS JavaScript Články Ostatní

Články Katalog zdrojů SEM SEO

Jak psát web píše Yuhů, Dušan Janovský. Kontakt.