04 augusti, 2010

XHTML/Javascript: Ej blockerad nedladdning och optimering av websida när Javascript och CSS används

English title: Non-Blocking download and optimization of webpages when using Javascript and CSS

Förord
Är du webbutvecklare/webbdesigner som vill att din websida ska ladda snabbare? Använder du skript som tar lång tid att ladda? Då kanske du finner din lösning här. Fortsätt läs för att få veta mer.


Introduktion
När en webbsida laddas i en webbläsare skickas det ett anrop för varje skript, stilmal och bild som existerar i koden för webbsidan. När skript och stora stilmallar måste hämtas och läsas in tar det tid. Detta blockerar webbläsaren från att fortsätta tills nedladdningen av filerna är klara. Om man då har ett stort skript som måste laddas in först, börjar text och bilder inte synas förrän den har laddat klart.

Lösningen? Komprimera skript och stilmallar för att minska på filstorleken och försök få allt att laddas ned samtidigt. Försök också att ha så får anrop som möjligt. Webbläsarna använder mestadels GET- och POST-anrop och de bör hållas till ett minimum.

Tipsen i denna artikel kan även användas på webbsidor anpassade för mobiltelefoner och t.ex iPad, som är begränsade till hastigheter inom GSM/GPRS/3G/4G som varierar mycket beroende på var man befinner sig geografiskt. De har även i många fall sämre RAM och CPU-kraft som krävs för att rendera webbsidor. Färre anrop förbättrar upplevelsen.


Tester
Jag har utfört tre tester på min egna webbsida med följande uppsättning:
  • Firefox 3.6.8
  • Firebug 1.5.4
  • PHP (957 b)
  • XHTML Strict
  • CSS (883 kB)
  • Javascript (310 kB)
  • Stor bild (2.7 MB)

Att tänka på innan man börjar
Javascript brukar vara stora och ta upp mycket utrymme samt ha tunga beräkningar. Se till att komprimera alla skript så de tar upp så lite utrymme som möjligt. Då går det snabbare att ladda in dem.

Min fil med Javascript är bara komprimerad till hälften och innehåller många olika skript och bibliotek som har infogats i en enda fil istället för att använda flera.

Istället för:
<script type="text/javascript" src="skript1.js"></script>
<script type="text/javascript" src="skript2.js"></script>
<script type="text/javascript" src="skript3.js"></script>
<script type="text/javascript" src="skript4.js"></script>
<script type="text/javascript" src="skript5.js"></script>

Använder jag:
<script type="text/javascript" src="alla_skript.js"></script>

Detsamma gäller också för alla mina stilmallar. Använd inte "@import" i CSS för att ladda in externa stilmallar. Det skapar extra anrop i vissa webbläsare. Ni bör avstå från det. Det bästa är att sammanfoga alla stilmallar till en enda stilmall.


Komprimering
Många webbapplikationer, webbtjänster och skript erbjuder möjligheten att komprimera (minska) filernas storlek. Här är ett exempel på en sökning

För er som vill testa på att komprimera skript med PHP kan läsa följande artikel http://www.devirtuoso.com/2009/07/how-to-compress-cssjavascript-files-with-php/


Laddningstider och blockering av laddning
http://www.stevesouders.com/blog/2009/04/27/loading-scripts-without-blocking/ är en av de bästa artiklarna jag har läst som beskriver vad ämnet handlar om och vad man kan använda för att lösa problemen.

En lösning som jag har börjat använda är enkel att använda och effektiv. Metoden kallas "Script DOM Element" och går ut på att man med hjälp av lite Javascript, inuti head-sektionen på en webbsida, kan skapa en skript-tagg dynamiskt när webbsidan börjar laddas. Man anger att källan (eng. source, xhtml. src) ska peka mot skriptfilen.

Då skapar man parallell nedladdning i webbläsaren, det vill säga att skriptet laddas ned samtidigt som resten av sidan.

Viktigt! Lösningen med "Script DOM Element" varierar mellan olika webbläsare och jag rekommenderar att ni läser artikeln jag nämnde ovanför och tar en titt på bilden här http://stevesouders.com/efws/images/0405-load-scripts-decision-tree-04.gif Det har att göra med om skriptet ligger på samma domän som webbsidan eller inte, samt om inbäddade skript är beroende av skriptet eller inte.


Förklaring av mitt test
Jag utförde tre tester i webbläsaren Firefox version 3.6.8 och till min hjälp använde jag Firebug version 1.5.4 för att ta tid och för eventuell felsökning. I Firebug kan man se fina grafer över nedladdningen av webbsidan. Man kan se vilka delar i koden som tar längst respektive kortast tid att utföra. Mer information om tester hittar ni under rubriken Scenario.

Exempel på graf i Firebug

(Klicka på bilden för att förstora)

I graferna kan man se vilket svar man fick från webbservern (Response, GET, POST, 404, 200, 304, m.fl) samt tiden. Det bästa är om stilmallar, skript och bilder kan laddas ned parallellt (samtidigt).

Viktigt
Innan varje test utförs måste man rensa webbläsarens cache och Internetfiler för den aktuella dagen. Annars får man cachade filer vilket ger ett vilseledande resultat. I Firefox görs det via menyn:
  1. Verktyg
  2. Rensa ut tidigare historik
  3. Välj Idag
  4. Kryssa för Besökta sidor och filhämtningshistorik samt Cache.



Så glöm inte rensa webbläsarens cache!!

Testerna påverkas även av din Internethastighet. En annan notering är att kommentarerna i min kod i testet är på engelska för att hjälpa engelska besökare som läser artikeln.


Scenario
Preparera en webbsida med lite text, en stor bild som helst ska vara minst 1MB, en stor stilmall och ett stort Javascript. Då ser man skillnanden tydligt och millisekunder är svårt att mäta eftersom det kan skilja ganska många från test till test. Ni kan referera till min kod som jag visar under testerna här nedanför.

I vanliga fall laddas objekten och resurserna i följande ordning.
  1. CSS och Javascript laddas parallellt
  2. Bilder laddas sist, ibland även text.
Men som jag sagt tidigare i artikeln, blockerar oftast Javascriptet resten av webbsidan från att börja ladda.


Test 1
En vanlig implementation av en webbsida.

Följande kod användes i testet:
<?php
//
// Test 1
// File: test.php
//
header("Cache-Control: no-cache");
header("Pragma: no-cache");
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>Testa laddning av Javascript</title>
<link rel="stylesheet" type="text/css" media="all" href="css2.css" />
<script type="text/javascript" src="javascript2.php"></script>
</head>
<body>
<p>Text som visas på hemsidan snabbt.</p>
<p><img src="stor_bild.jpg" alt="stor bild" width="700" /></p>
<p>Sista texten</p>
</body>
</html>

Resultat - Test 1

(Klicka på bilden för att förstora och se resultatet)

Beskrivning av resultatet
Vi ser att stilmallen och Javascriptet laddas parallellt medan bilden laddas senare (sist). På vissa webbsidor kan skripten vara sega och då tar det längre tid för hela webbsidan att laddas. Detta vill vi ändra på.


Test 2
Nu använder vi tekniken "Script DOM Element" för både stilmallen och Javascriptet. Tänk på att även använda taggen "noscript" om en besökare har en webbläsare med Javascript avstängt. Då måste de fortfarande kunna använda stilmallen som annars slutar fungera eftersom den inte kan laddas korrekt.

Följande kod användes i testet:
<?php
//
// Test 2
// File: test2.php
//
header("Cache-Control: no-cache");
header("Pragma: no-cache");
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />

<title>Testa laddning av Javascript</title>
<noscript>
<link rel="stylesheet" type="text/css" media="all" href="css2.css" />
</noscript>
<script type="text/javascript">
/* <![CDATA[ */

// If you are using both CSS and JS DOM load, then you need to put the CSS link also inside a noscript tag

// CSS
var domscript_css = document.createElement('link');
domscript_css.rel = "stylesheet";
domscript_css.type = "text/css";
domscript_css.media = "all";
domscript_css.href = "css2.css";
document.getElementsByTagName('head')[0].appendChild(domscript_css);

// Javascripts
var domscript = document.createElement('script');
domscript.type = "text/javascript";
domscript.src = "javascript2.php";// Contains all Javascript
document.getElementsByTagName('head')[0].appendChild(domscript);
/* ]]> */

</script>
</head>
<body>
<p>Text som visas på hemsidan snabbt.</p>
<p><img src="stor_bild.jpg" alt="stor bild" width="700" /></p>

<p>Sista texten</p>
</body>
</html>

Resultat - Test 2


(Klicka på bilden för att förstora och se resultatet)

Beskrivning av resultatet
Nu ser vi att hela webbsidan laddas samtidigt och stilmallen och Javascriptet laddas ned parallellt. Detta kallas på engelska för "Non-Blocking Javascript" eftersom det gör att resten av webbsidan inte blockeras. Notera att det bara tar så lång tid det tar att läsa in filen test2.php och bilden. Vi har just nu minskat våra laddningstider med en hel sekund (1 sekund) om vi jämför med föregående Test 1.


Test 3
I det sista testet länkar jag till stilmallen precis som vanligt men Javascriptet laddas in dynamiskt. Ett tips är att alltid ladda in stilmallar innan skript.

Följande kod användes i testet:
<?php
//
// Test 3
// File: test3.php
//
header("Cache-Control: no-cache");
header("Pragma: no-cache");
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>Testa laddning av Javascript</title>
<link rel="stylesheet" type="text/css" media="all" href="css2.css" />
<script type="text/javascript">
/* <![CDATA[ */

// Javascripts
var domscript = document.createElement('script');
domscript.type = "text/javascript";
domscript.src = "javascript2.php";// Contains all Javascript
document.getElementsByTagName('head')[0].appendChild(domscript);
/* ]]> */

</script>
</head>
<body>
<p>Text som visas på hemsidan snabbt.</p>
<p><img src="stor_bild.jpg" alt="stor bild" width="700" /></p>

<p>Sista texten</p>
</body>
</html>

Resultat - Test 3

(Klicka på bilden för att förstora och se resultatet)

Beskrivning av resultatet
I det sista testet var det stilmallen som tog tid att ladda in och blockerar därför resten av webbsidan.


Analys
Testen visade tydligt vilken skillnad det var om man använde tekniken eller inte, eller om man blandade tekniken med vanlig kodning. Tiderna i resultaten kan variera men ni får gärna räkna ut ett genomsnittlig tid för varje test och sedan jämföra dem.

Nu testade jag med en extremt liten webbsida med endast två stycken och en bild. Stilmallen lästes in men användes inte på webbsidan. Om man testar med en större webbsida, tror jag man får bättre resultat och man upptäcker nog även enklare eventuella prestandaförbättringar.

Kontrollera även cache mm
Om det tar tid att ladda in koden skriven i HTML/XHTML varje gång en sida laddas, ska man tänka på följande:
  • Hämtas data från ren HTML?
  • Hämtas data från en databas (XML, MySQL, MS Access, MS SQL Server, ...)?
  • Används cache på servern?
  • Används cache på klienten?
  • Hur länge är ett objekt eller en resurs cachad?
  • Är data komprimerat eller i klartext?
  • Är data krypterad (ex. HTTPS, CHAP)?
Cachad data hjälper till att öka prestandan oerhört mycket och det märks tydligt på användningen av minne och processor på servern. Kryptering och omkodning av data kan också ta tid. Komprimera data om det är möjligt.

Snabbt om data redan finns i cache
Testerna visade att det bara tog några millisekunder att ladda webbsidan om man glömde rensa cache och Internetfiler innan man utförde varje test.

Tänk på antalet besökare
Om man inte har så många skript tror jag inte man behöver tänka på detta, men då måste man istället tänka på hur många besökare som besöker webbsidan. Om väntetiden är för lång när man laddar en webbsida (absolut max 10 sekunder enligt vissa rapporter) förlorar man besökare. För många företag betyder det förlust i intäkter och mindre pengar.

Låsning och blockering
Om ett skript låser sig i en evig loop eller om skriptet måste beräkna tunga data innan webbsidan laddas, blockeras resten av innehållet.

Kommer det fungera på din webbsida?
Kontrollera först noga om metoden ovan i testerna kommer fungera på just din webbsida eller i ditt scenario. Det finns vissa begränsningar som beskrivs i de andra artiklarna jag länkade till.

Testat i andra webbläsare?
Testerna har endast utförts i Firefox för att jag inte har haft tillgång till andra webbläsare, utom Internet Explorer. Jag vet inte riktigt om det finns något insticksprogram tillInternet Explorer


Slutsats
Min slutsats av testerna och analysen är att man först måste tänka på om det lönar sig att använda metoden. Metoden fungerar bra och jag kommer använda den när jag utvecklar mina webbapplikationer.

Lycka till

Välkomna till bloggen

Välkomna ska ni vara kära besökare. Jag skriver om IT för att det är kul och för att jag vill dela med mig av information och kunskap. Jag försöker hålla bloggen så kategoriserad som möjligt för att ni enklare ska hitta intressanta länkar och artiklar.