Tijdschrift voor webwerkers » Artikel #122
Er zijn meerdere factoren die invloed hebben op hoe snel een pagina geladen en getoond wordt. We kijken naar deze factoren, en naar hoe je er zó mee om kunt gaan dat je een optimale performance haalt.
De performance van een webpagina hangt om te beginnen af van de totale zwaarte van die pagina. Maar er zijn méér factoren die verrassend veel invloed kunnen hebben op hoe snel een pagina geladen en getoond wordt. In dit artikel kijken we naar al deze factoren, en naar hoe je er zó mee om kunt gaan dat je een optimale performance haalt.
Als we kijken naar hoe snel een pagina na een klik op een link getoond wordt, dan zijn er grofweg drie factoren van belang: server-verwerkingstijd, -downloadtijd en tekentijd. In dit artikel zal ik server-verwerkingstijd en de tekentijd buiten beschouwing laten. Over het algemeen kun je wel zeggen dat server-verwerkingstijd (de hoofdredacteur houdt ervan als we zo min mogelijk Engelstalig jargon gebruiken) beneden de seconde zou moeten liggen. De tijd die het een browser kost om een pagina te tekenen is afhankelijk van meerdere factoren zoals – bijvoorbeeld – de inzet van Javascript en (geneste) tabellen. In dit artikel concentreer ik me op downloadtijd.
Heel kort door de bocht kun je zeggen dat downloadtijd te berekenen is door totale zwaarte van de gehele pagina te delen door de bandbreedte. Als we de bandbreedte voor dit artikel als vaststaand beschouwen, dan blijft alleen de totale zwaarte van de pagina over als factor in de downloadtijd. Echter, dit blijkt net iets té kort door de bocht te zijn. Om goed te kunnen berekenen hoeveel tijd het laden van een totale pagina kost moeten we ons enigszins verdiepen in het HTTP protocol.
Een pagina bestaat naast het HTML document uit een aantal elementen (JavaScript, CSS, GIF, etc.), voor welke allemaal een aparte HTTP verbinding wordt geopend. Vóór HTTP (versie) 1.1 was dit ook een aparte TCP/IP verbinding. Met HTTP 1.1 ‘persistent connections’ en ‘pipelining’ (waarbij een TCP/IP verbinding een tijdlang wordt opengehouden voor volgende HTTP verbindingen), is dit niet altijd het geval. Zo is ten opzichte HTTP 1.0 een besparing van 25 tot 30% gerealiseerd.
Per HTTP request (verzoek om een bestand door de browser) en response (antwoord van de server) wordt ook een ‘header’ overgestuurd. In de request header staat bijvoorbeeld het pad naar het bestand, de useragent (browserversie en -type) en eventuele cookies. In de response header staat bijvoorbeeld de HTTP response code, eventueel het zetten van cookies en mimetype bestandssoort, bijvoorbeeld “text/html”
).
Als we nu naar de downloadtijd kijken, dan zijn naast totale zwaarte de volgende factoren van invloed:
Zoals uit de omschrijving van het HTTP protocol bleek wordt per onderdeel van een pagina een HTTP verbinding opgebouwd, en hiervoor misschien een TCP/IP verbinding. Het opbouwen van een TCP/IP-verbinding kost in Nederland ongeveer 60 milliseconden, voor grotere netwerkafstanden kan dit oplopen tot 200 milliseconden. Browsers openen vaak maar een beperkt aantal simultane verbindingen. En daarom zorgt een groot aantal elementen voor vertraging, puur vanwege alle verbindingsoverhead.
Daarnaast heeft ieder HTTP request en response de al eerder genoemde header, die 200 tot 400 bytes toevoegt aan iedere download. Als een pagina bijvoorbeeld uit 50 elementen bestaat, dan wordt er zo 10 tot 20 kilobyte aan header-informatie toegevoegd. Dit alles zorgt ervoor dat veel kleine elementen véél meer tijd kosten om te downloaden dan weinig grote elementen. Het is dus een goed idee om daar zorgvuldig mee om te gaan.
Niet iedere keer dat een browser een bestand opvraagt zal de browser het bestand ook daadwerkelijk downloaden: soms wordt het uit de browser cache gehaald. Dat kan de performance verbeteren.
Er zijn echter weinig absolute zekerheden over caching: verschillende browsers gecombineerd met verschillende instellingen zorgen voor onvoorspelbare resultaten. Je kunt de caching enigszins sturen met HTML meta-tags en response headers, maar browsers volgen deze tags niet altijd.
Daarnaast zijn er 2 vormen van caching: volledige caching, zonder enige communicatie met de server, en caching met een server check. Bij de laatste variant wordt bij het versturen van het HTTP request in de header aangegeven dat het bestand alleen gedownload hoeft te worden indien dit bestand niet is veranderd sinds de ‘lastmodified datetime’. Als de server geen nieuwere versie kent wordt geen data, maar alleen een response header teruggestuurd. In die response header wordt dan aangegeven dat er geen veranderde versie bestaat.
Als het bestand een statisch bestand is dat geen server verwerking vereist (zoals bijvoorbeeld HTML of GIF bestanden) zal de web server vaak de lastmodified datetime van het fysieke bestand meegeven en daarmee caching faciliteren. Voor dynamische bestanden geldt dat een server normaal gesproken geen lastmodified datetime meegeeft. Dit is wel te bewerkstelligen, bijvoorbeeld voor een J2EE applicatie met filters.
Moderne browsers zijn redelijk intelligent qua caching. Elementen op een pagina, zoals .gif
, .css
of .js
bestanden, worden vaak (volledig) gecached, terwijl de pagina zelf vers van de server wordt opgehaald. Vooral wanneer de server een goede lastmodified datetime meegeeft worden dit soort bestanden maar één keer gedownload.
Structuur en layout van een site veranderen vaak weinig, en content wél. Daarom is het dus beter om deze scheiding ook in de losse elementen door te voeren: hierbij staat content in de (dynamische) pagina (HTML), terwijl de layout in losse stylesheets beschreven wordt. Hoe meer layout je uit de HTML haalt en in de stylesheets plaatst, hoe sneller een pagina zal laden zodra de CSS bestanden gecached zijn.
Nadeel van grote CSS bestanden is wel dat de eerste keer downloaden ervan veel tijd kost. Als bijvoorbeeld alle CSS bestanden al op de homepage geladen worden, betekent dit dat een gebruiker lang moet wachten voordat de eerste pagina staat.
Een factor die een grote rol kan spelen is compressie. Compressie? In webpagina’s? Compressie in andere gebieden kent iedereen goed, bijvoorbeeld door de inzet van Winzip voor Zip bestanden. Andere formaten zoals GIF of JPeg bevatten ook compressie. Zo maakt GIF gebruik van precies hetzelfde algoritme (LZW) als het Zip formaat (wat verklaart waarom je 0% besparing krijgt als je GIF bestanden comprimeert tot een Zip bestand).
HTTP 1.1 ondersteunt ook compressie. Hoewel 1.1 al lang bestaat was (correcte) ondersteuning voor compressie door zowel servers als browsers beperkt. De laatste jaren is hier verandering in gekomen, en kun je er vanuit gaan dat het merendeel van de browsers en servers goede ondersteuning voor compressie kennen.
Hoe werkt compressie? Bij het versturen van een HTTP request geeft de browser aan in de request header dat deze compressie ondersteunt. Als de server deze request ontvangt (en compressie geactiveerd is) zal de server eerst kijken of er een gecomprimeerde versie van het bestand voorhanden is. Zo ja, dan wordt deze meteen overgestuurd, zo nee dan wordt het bestand eerst gecomprimeerd en vervolgens overgestuurd. De browser ontvangt het bestand, decomprimeert het en toont het tenslotte. De eindgebruiker merkt hier weinig van, alleen dat een site beter presteert. Processorkracht aan de kant van de gebruiker is namelijk tegenwoordig voldoende voor handen.
Voor de webserver is compressie wel een stuk zwaarder. Daarom kun je er soms beter voor kiezen om dynamische bestanden (die per request veranderen) niet gecomprimeerd over te sturen, aangezien deze niet in gecomprimeerde vorm gecached kunnen worden als ze iedere keer vernieuwd moeten worden.
Daarnaast lenen ook niet alle bestandstypen zich voor compressie. Compressie wordt vaak in gZip formaat toegepast, wat weer een variant van het Zip formaat is. Bijvoorbeeld, GIF bestanden worden nauwelijks kleiner door het gebruik van compressie, terwijl je bij tekstformaten een reductie van 50 tot 80% kunt behalen.
Er zijn nog meer factoren die performance van webpagina’s verbeteren, zoals de keuze voor minder plaatjes op pagina’s, gebruik van RIA technologie, Flash of de inzet van (reversed) proxy servers. Maar keuzes rond dit soort factoren zijn een stuk fundamenteler en worden vaak niet alleen gemaakt door de individuele frontend ontwikkelaar.
Het optimaliseren van een website voor performance kan ook nadelige effecten hebben op de structuur en de leesbaarheid van code. En dat kan er weer voor zorgen dat de onderhoudbaarheid en uitbreidbaarheid van een site verminderd worden. Ook kunnen CMS’en speficieke eisen stellen aan de HTML structuur. Het is een kwestie van keuzes maken en van altijd blijven kijken naar de specifieke eisen voor de desbetreffende site.
Om een goed presterende web site te ontwikkelen kun je de volgende dingen doen:
/home.gif?r=0.56849
is voor de dot-com hype begonnen, zat erin en doet het nog steeds als Java specialist bij Lost Boys. Daar is hij verantwoordelijk voor software architectuur, kennisontwikkeling en –deling op het gebied van Java, en het vliegende keep spelen bij onoplosbare problemen.
Publicatiedatum: 15 maart 2006
Naar Voren is op 18 juli 2010 gestopt met publiceren. De artikelen staan als een soort archief online. Het kan dus zijn dat de informatie verouderd is en dat er inmiddels veel betere of makkelijkere manieren zijn om je doel te bereiken.
Copyright © 2002-heden » NAAR VOREN en de auteurs