Posts tonen met het label Javascript. Alle posts tonen
Posts tonen met het label Javascript. Alle posts tonen

donderdag 3 september 2009

JavaScript laden zonder de browser te blokkeren


Er zijn heel veel factoren die invloed hebben op de snelheid waarmee een webpagina wordt afgebeeld. Zaken zoals het aantal requests per pagina, het wel of niet gebruik maken van een Content Delivery Network, het instellen van gzip voor bepaalde type content en een juiste plaatsing van scripts en stylesheets in de pagina, dragen allemaal bij aan de ervaring die de gebruiker heeft als hij de pagina opvraagt. Als de ontwikkelaar te veel van deze zaken fout aanpakt, dan zal hij de woede van de gebruiker op zijn hals halen en wellicht hevig bloedend ergens in een greppel treurig aan zijn einde komen.

Er zijn twee lekker pragmatische en niet te dikke boeken over deze onderwerpen geschreven die ik even wil aanstippen: “High Performance Web Sites” en “Even Faster Web Sites”, beide van Steve Souders (http://stevesouders.com/hpws/rules.php). Beide boeken zijn binnen ISAAC in ieder geval verplichte kost voor alle web develeopers.

In deze blogpost wil ik een van de technieken uit het tweede boek kort introduceren: “JavaScript laden zonder de browser te blokkeren”. Het probleem dat hier speelt is dat scripts die worden geladen m.b.v. een SCRIPT tag tot gevolg hebben dat de browser helemaal niets anders zal downloaden tijdens het laden en interpreteren van deze code. Dit alles kan resulteren in een significante verlenging van de laadtijd en dus tot een tragere pagina. Zonde, want browsers kunnen in theorie meerdere bestanden parallel downloaden.

De reden dat de browser niets anders downloadt is dat de JavaScript die op dat moment wordt gedownload de rest van de pagina kan wijzigen na executie. Het aantal en de volgorde van de andere resources kan afwijken van wat er in de oorspronkelijke HTML is gespecificeerd (bv met de document.write(…) constructie). Dit wijzigen van de HTML is in het overgrote deel van de gevallen helemaal niet aan de orde en resulteert dus in een onnodig lange laadtijd. Daarnaast is de volgorde waarin externe JavaScript bestanden zijn gedefinieerd in de HTML tevens de volgorde waarin ze moeten worden geëxecuteerd door de browser. Deze executievolgorde is eigenlijk niet van belang voor de volgorde waarin de scripts worden gedownload, iets dat tot nu toe alleen de ontwikkelaars van IE8, Safari 4 en Chrome 2 hebben begrepen: deze browsers ondersteunen het parallel downloaden van scripts wel. Andere resources worden echter wel nog steeds geblokkeerd.

In “Even Faster Web Sites” worden een aantal technieken geïntroduceerd die dit probleem (ten dele) oplossen. Ik zal deze hier kort introduceren. Voor de details verwijs ik echter door naar het boek zelf.

XHR Eval.
In deze techniek worden de scripts met een XMLHttpRequest gedownload en vervolgens met een aanroep van eval() geïnterpreteerd. Dit werkt: de browsers blokkeren het downloaden van de andere resultaten niet. Het grote probleem is echter dat je op deze manier alleen scripts kan laden die van hetzelfde domein komen als de pagina zelf.

XHR Injection
Deze methode lijkt enigszins op de voorgaande: het script wordt geladen mb.v. de XMLHttpRequest functie, maar wordt geëxecuteerd door een SCRIPT tag in de DOM te creëren en de gedownloade code daarin te injecteren. Deze methode is soms iets sneller dan het gebruik van eval(), maar lijdt onder dezelfde beperkingen.

Script in Iframe
Iframes worden parallel geladen met andere componenten op een pagina. Door in iframe’s HTML pagina’s te laden die verwijzen naar de gewenste scripts, worden deze scripts dus parallel gedownload. Ook deze techniek is beperkt tot scripts die op hetzelfde domein staan als de hoofdpagina zelf. Bovendien moet de code worden aangepast om een verbinding tussen de hoofd- en de iframepagina te leggen.

Script DOM Element
Als alternatief voor het initieel opnemen van een SCRIPT tag in de HTML, kan er ook een on-the-fly worden gecreëerd m.b.v. document.createElement(…). Deze tag wordt dan dynamisch voorzien van een src attribuut en vervolgens in de HTML geïnjecteerd. Deze methode is geschikt voor scripts die komen van een andere domein dan het domein van de pagina zelf.

Script defer
IE ondersteunt het DEFER attribuut bij de SCRIPT tag. Defer is een indicatie aan IE dat het gerefereerde script geen DOM wijzigingen zal uitvoeren en dat het niet meteen hoeft te worden gedownload. Dit heeft tot gevolg dat IE andere bestanden parallel met dit script zal downloaden. Het werkt echter alleen in IE en enkele nieuwe browsers.

Document.write Script tag
In deze techniek wordt net als bij de “Script DOM Element” methode een SCRIPT tag dynamisch aan de HTML toegevoegd, dit keer echter met een document.write() constructie. Het verschil is dat deze techniek alleen resulteert in het parallel downloaden van andere scripts, alle andere bestanden worden toch geblokkeerd.

Conclusie
Na het lezen van de technieken lijkt het redelijk simpel: kies altijd voor de “Script DOM Element” methode. De realiteit is echter niet zo eenvoudig. De keuze hangt af van het gewenste gedrag van de “busy indicators” in de browser (de visuele hints die aangeven dat er iets wordt gedownload) en van de wens om de download- en executievolgorde af te dwingen. Voor meer details over wanneer je nou precies wat moet kiezen verwijs ik je graag door naar hoofdstuk 4 van “Even Faster Web Sites”.

vrijdag 3 juli 2009

Website optimalisatie

foto door: Dave & Karin
Moderne websites zitten tjokvol afbeeldingen en "rich" onderdelen (javascript libraries als JQuery of Dojo) en hoewel bijna iedereen tegenwoordig ultrasnelle internet verbindingen heeft is het aan te raden om je website te optimaliseren. Door dit te doen laadt de pagina sneller en is de user-experience dus beter. Een goed begin om iets over website optimalisatie te leren is door het boek "High Performance Websites" te lezen. Hierin staat in detail uitgelegd waar je op moet letten bij het maken van een website. Hieronder vind je een overzicht van de grootste snelheidswinsten die je kunt behalen.

- Het aantal HTTP requests beperken
- Javascript en CSS verkleinen
- De site gzippen
- CSS sprites gebruiken

Hiernaast zijn er nog veel meer mogelijkheden om snelheid te winnen, zoals het plaatsen van css files bovenaan in de webpagina en javascripts juist onderin, het vermijden van CSS expressies en redirects voorkomen. Maar we beperken ons nu tot de bovenstaande technieken omdat deze de grootste winsten boeken.
Het aantal requests beperken kan een behoorlijke winst opleveren. Stel dat je site zes javascript files inlaad. Hiervoor zijn dus ook zes requests nodig. Deze requests zitten op elkaar te wachten en dit kan dus voor een behoorlijke vertraging zorgen. Het aantal request kun je beperken door de zes javascript files te bundelen tot een enkele file. Dit zorgt ervoor dat de scripts niet op elkaar hoeven te wachten en met 1 request ingeladen kunnen worden. Naast de javascript bestanden kun je ook kijken naar de stylesheets die worden ingeladen en afbeeldingen. Afbeeldingen kun je ook bundelen tot een enkele afbeelding met behulp van CSS sprites. Een CSS sprite is eigenlijk een grote afbeelding met alle afbeeldingen op de site naast elkaar. Door in je CSS aan te geven waar je afbeelding begint, kun je de enkele afbeelding voor alle afbeeldingen op de site hergebruiken en hoeft er dus maar 1 afbeelding ingeladen te worden.

Naast het verminderen van het aantal requests die gedaan worden kan ook het verminderen van de hoeveelheid data een snelheidswinst opleveren. De hoeveelheid data die je verzend kun je verminderen door, bijvoorbeeld, javascript en css bestanden te "minify-en". Je haalt dan alle overtollige tekens uit de bestanden (zoals enters, spaties, opmerkingen) waardoor de files stukken kleiner worden. Daarnaast kun je de hoeveelheid data verminderen door de site te g-zippen. gzip is een protocol die door de meeste browsers wordt ondersteund en de hoeveelheid data met 70 tot 80 procent kleiner kan maken.

vrijdag 8 mei 2009

Forms controleren met JQuery


JQuery maakt het gebruik van Javascript in websites eenvoudiger met een kleine core library die is uit te breiden met plugins. Deze plugins zijn beschikbaar voor haast alles wat je mogelijk zou willen doen. Zo ook voor het valideren van formulieren. Hiervoor zijn meerdere plugins beschikbaar maar de beste is toch wel de "validation" plugin. Met deze plugin is het mogelijk om met slechts een enkele regel javascript een eenvoudige controle uit te voeren op een formulier. Je controleert dan enkel of een aantal velden zijn ingevuld. Complexere controles zijn mogelijk door regels en functies toe te voegen aan de validatie.

Stel je hebt het volgende formulier op je site:

<form id="formulier">
  <input type="text" name="voornaam" id="voornaam" />
  <input type="text" name="achternaam" id="achternaam" />
  <input type="submit" value="opslaan" />
</form>

Om op dit formulier te controles toe te voegen zijn twee stappen nodig:

  • de verplichte velden moeten de class "required" krijgen

  • met een regel javascript moet worden aangegeven dat het formulier gecontroleerd moet worden


  • De eerste stap is eenvoudig, stel "achternaam" is verplicht, ons formulier ziet er dan als volgt uit:

    <form id="formulier">
      <input type="text" name="voornaam" id="voornaam" />
      <input type="text" name="achternaam" id="achternaam" class="required" />
      <input type="submit" value="opslaan" />
    </form>

    de tweede stap zetten we in de "ready" methode van jquery:

    <script>
      $(document).ready(function(){
        $("#formulier").validate();
      };
    </script>

    Dat is alles, wanneer de gebruiker nu het veld "achternaam" niet invult krijgt hij de melding dat het veld verplicht is. Naast "required" zijn er meer classes beschikbaar in de plugin, zoals "email" voor het valideren van e-mailadressen, "url" voor het valideren van url's, enz. Naast deze standaard methoden kun je ook je eigen toevoegen. Laten we zeggen dat "achternaam" niet alleen verplicht is, maar ook alleen letters mag bevatten. We kunnen dan onze eigen methode maken om dit te controleren.

    <script>
      $.validator.addMethod('tekst', function (value) { return /^[A-Za-z]*)$/.test(value) }, 'Achternaam mag alleen tekst zijn');
    </script>

    De bovenstaande code voegt een methode toe om dit te doen met de naam 'tekst'. Hiervoor gebruik je de methode "addMethod()" waar je drie parameters aan meegeeft. Als eerste de naam van de nieuwe methode. De tweede parameter is een functie die de controle uitvoert en een true teruggeeft als de meegegeven waarde voldoet en een false als hij niet voldoet. De laatste parameter is de foutmelding die getoond moet worden. Na de methode toegevoegd te hebben kan de naam ("tekst" in dit geval) samen met de andere functies als class aan een inputveld toegevoegd worden.

    Naast het toevoegen van methodes is er ook nog de mogelijkheid om regels toe te voegen. Regels kunnen worden gebruikt om een functie ergens van afhankelijk te maken. Bijvoorbeeld, stel we willen wel dat "achternaam" verplicht is, maar alleen als er niks is ingevuld bij "voornaam". We kunnen dan aan de methode "validate()" een regel toevoegen die dit controleert.

    <script>
      $(document).ready(function(){
        $("#formulier").validate({
          rules: {
            achternaam : {
              required: {
                depends : function() { return ($("#voornaam").val() == '');}
              }
            }
          }
        });
      };
    </script>

    De bovenstaande code voegt de regel voor "achternaam" toe. hierin staat een "depends" (een afhankelijkheid) die controleert of de ingevulde waarde bij "voornaam" leeg is of niet.

    Als laatste willen we natuurlijk een aangepaste foutmelding tonen als achternaam niet is ingevuld. Ook dit voegen we toe aan de validate methode, achter de rules.

    <script>
      $(document).ready(function(){
        $("#formulier").validate({
          rules: {
            achternaam : {
              required: {
                depends : function() { return ($("#voornaam").val() == '');}
              }
            }
          },
          messages: {
            required: "Dit veld is verplicht"
          }
        });
      };
    </script>

    In het messages blok kunnen we een opsomming maken van alle methodes die we in de classes invullen met daarachter een tekst. Deze tekst wordt getoond wanneer de validatie op dit punt niet goed gaat.

    Dit is de basis van de functionaliteit van de validation plugin, natuurlijk is nog meer mogelijk dan alleen het bovenstaande, maar hiermee vang je 99% van de formulier-validaties op.

    woensdag 25 februari 2009

    Safari 4 public beta: benchmark time!

    Today Apple released the latest version of their browser: Safari 4. It's only a public beta but with an impressive list of new features including a JavaScript engine that is 4.5 times faster than the previous Safari version, I couldn't resist: benchmark time!


    For this benchmark I used the webkit SunSpider benchmark. This benchmark only tests the core JavaScript language, not the DOM or other browser APIs. Looking at the current RIA trend this makes sense: more and more of the application logic (and therefore data structure) is being run inside the browser, so core data structure manipulation will become much more important in the future.


    The benchmark runs a couple of tests that consist of crypto and 3d calculations, some bit operations, string and date manipulations, recursion, and object access tests. It returns the time it took to complete each test and the sum of all the tests is the overall score. Here is an example of one of my runs on safari 4 (time in milliseconds). 


    For the benchmark I used my Dell latitude D830, running Windows XP. I tested the following 5 browsers:


    - The new Safari 4

    - Google Chrome 1.0

    - IE 7

    - IE 6

    - Firefox 3.0

    - Opera 9.6


    After running the same test 5 times in each of the browsers I found the following results (lower bar is better)




    In my very non-scientific tests the new Safari 4 is just a fraction faster than Google Chrome and about 2.2 times faster than Firefox and Opera. But it's much much faster than IE6 and IE7: a whopping 13 times on my machine.


    Apple itself claims to be 3 times faster than Firefox and even 30 times faster than IE7, using SunSpider and iBench as benchmarks. My findings where not this extreme, but impressive nonetheless.


    I guess Google's goal to raise the bar on JavaScript performance was a success. With their dependance on fast JavaScript for all their cloud apps I guess they are the ones that will be most pleased with this new version of Safari.


    Oh, and don't forget our ultimate benchmark. Yeah baby!

    zondag 21 december 2008

    Raycasting in Javascript



    Het was ongeveer een week geleden dat mijn gedachte tijdens het spelen van Fable 2 afdwaalde naar de computerspelletjes van lang vervlogen tijd. Spelletjes zoals Doom en Wolfenstein 3d zagen er in hun primitiviteit karakteristieker uit dan de gemiddelde shooter van het afgelopen jaar. Toch was het technisch gezien ongelooflijk simpel om het 3d effect uit Wolfenstein te creëren. Zo eenvoudig dat ik het in een middagje na heb gemaakt in Javascript.

    De techniek die Wolfenstein gebruikte om een 3d omgeving te renderen heet “Raycasting”. Vanuit het punt van de speler (de camera) ga je een lijn trekken en kijk je hoever je die lijn door kunt trekken totdat je een muur (of iets anders) tegenkomt. De afstand tussen de speler en deze muur gebruik je om te bepalen hoe hoog dat stukje muur moet zijn. Kleine afstanden zorgen voor een hoge muur en grote afstanden voor een kleine muur (objecten lijken immers kleiner naarmate ze verder weg staan). Dit doe je vervolgens voor het hele blikveld van de speler en het effect is klaar. Het resultaat van het raycasting in javascript experimentje mag er zijn, ondanks dat het in veel browsers behoorlijk traag kan zijn (tip: bekijk hem in Google Chrome vanwege zijn ongelooflijk snelle javascript engine).

    maandag 15 oktober 2007

    Fout: object vereist


    Wie kent het niet? Je bent een stuk javascript code aan het maken en tijdens het testen verschijnt de foutmelding "fout: object vereist". Je krijgt dan de vraag of je wilt beginnen met foutopsporing en je bent dan eigenlijk altijd geneigd om op "Nee" te klikken, wetende dat de andere optie een of ander wazig programma start om vervolgens te crashen of zo. Voor de gein moet je eens op "Ja" drukken en dan de Microsoft Script Editor starten. Deze loopt door de code heen en stopt op de plaats waar de fout zit. Van hieruit kun je een heel aantal dingen controlleren. Zo kun je variabelen in javascript controlleren, hun waarden inzien en hun onderliggende structuur doorlopen. Zo kun je vrij goed opsporen waar de fout zit. Stiekem best handig dus.

    donderdag 30 augustus 2007

    Brengt Silverlight het licht?


    Afgelopen week kwam ik de site “tafiti” tegen. Een showcase van Microsoft om hun nieuwste product mee te demonstreren, Silverlight. Silverlight is, volgens Microsoft, een cross-browser, cross-platform plug-in voor de nieuwe generatie van media applicaties op het net. Het is het antwoord van Microsoft op Adobe’s Flash plug-in en het heeft daaraan een behoorlijke concurrent.

    Maar, het moet gezegd worden, tafiti ziet er best gelikt uit en het feit dat Silverlight naadloos met o.a. AJAX samen kan werken biedt potentie. Om een goed beeld van de mogelijkheden van Silverlight te krijgen ben ik er wat mee gaan stoeien. Het komt er uiteindelijk op neer dat je vooral XML en JavaScript code produceert die door de plug-in worden omgetoverd tot een mooi eindresultaat. Dit zorgt ervoor dat het geheel vrij eenvoudig is en je er snel inkomt. Daarnaast zorgt dit ervoor dat je geen aparte ontwikkeltool nodig hebt voor het maken van een Silverlight applicatie, je hebt aan een teksteditor genoeg. Het duurde ook niet lang of ik had een envoudige applicatie af. Trots keek ik naar het resultaat en vroeg ik me af of Microsoft hier daadwerkelijk die “Flash-killer” in handen had. Helaas kan ik die vraag niet met een volmondige “ja” beantwoorden. De opzet is goed, zeker voor programmeurs, maar het mist nog iets. Het zal met Silverlight best mogelijk zijn om mooie applicaties te bouwen, maar dat kan met Flash ook. Het samenwerken met AJAX klinkt ook heel interessant, maar dit kan met Flash en Flex ook. Microsoft heeft dus, voor mijn gevoel, nog niet de “Flash-killer” te pakken, maar ze komen akelig dicht in de buurt.