+++ title = "performance" draft = false tags = [ "code", "javascript", "performance" ] date = "2013-03-12" +++ # Javascript Performance :exclamation: **Best practices on performance**: zie http:*developer.yahoo.com/performance/rules.html en ook http:*sites.google.com/site/io/even-faster-web-sites ## Script volgorde 1. de `` tag wordt door de browser geparsed, inclusief sequentiëel alle ` ``` :exclamation: Dit werkt **niet**. Momenteel moet men twee `script` tags gebruiken... Stel u voor dat we jquery via `loadScript()` laden. Het zou kunnen dat bovenstaand script block dus uitgevoerd wordt voordat `$` gedefiniëerd is op toplevel scope. Oei. Nu zorgt de `src` attribute ervoor dat **altijd** eerst die externe resource volledig geladen is (jquery.js), vooraleer de interne tekst te evalueren (de CSS selector `.bla` tonen). Libraries bootstrappen kan je dus daarin doen, nadat ze geladen zijn. -> Indien het laden van de externe resource niet lukt, wordt de code die binnen de script tags staan ook __niet__ uitgevoerd! Een stap verder zou zijn de library zichzelf bootstrappen, door `loadScript()` lichtjes aan te passen: ```javascript function loadScript() { for(var i = 0; i < arguments.length; i++) { var js = document.createElement("script"); var head = document.getElementsByTagName("head")[0]; js.src = arguments[i].src; js.type = "text/javascript"; js.text = arguments[i].callback.toString(); head.appendChild(js); } } //usage: loadScript({ src: 'jQuery.js', callback: function() { $('.bla').show(); } }); ``` In de js file zelf kunnen we de tekst van de script tag die onszelf inlaadt (wow) dan evalueren ((Zie http://api.jquery.com/jQuery.globalEval/ - geen `eval()` hier dus): ```javascript // library code, blablablah var scripts = document.getElementsByTagName("script"); var curScript = scripts[ scripts.length - 1 ]; var script = curScript.innerHTML; if (script) { jQuery.globalEval(script); } ``` Zie ook http:*www.stevesouders.com/blog/2008/12/27/coupling-async-scripts/ en http:*ejohn.org/blog/degrading-script-tags/ voor meer info. ## Async Module Definition (AMD) pattern Zie presentatie hier: http://unscriptable.com/code/Using-AMD-loaders/#0 Komt op dit neer: ```javascript define(['dep1', 'dep2'], function(dep1ref, dep2ref) { function private() {} return { public1: "lala", public2: "loeloe" }; }); // more defines require('mod1', function(mod1ref) { // do stuff with mod1 }); ``` ## Head.js: parallel loading & serial executing http://headjs.com/ - Bevat een JS loader module dat *parallel* scripts laadt, maar in seriële volgorde de scripts uitvoert (of net niet). Zo heb je maar één script in de `` tag nodig om te laden voordat de rest van de pagina geladen wordt. Onderaan de pagina wordt de rest geladen met Headjs: ```javascript // use jQuery on the body of the page even though it is not included yet head.ready(function() { $("#my").jquery_plugin(); }); // load jQuery whenever you wish bottom of the page head.js("/path/to/jquery.js"); ``` Wat is allemaaal mogelijk? * Parellel laden + serieel uitvoeren (afhankelijk van elkaar in volgorde) * Serieel laden + serieel uitvoeren * JS feature checking * callbacks per script dat geladen is (evt gelabeled) * ... Dus nooit meer **zelf load scripts schrijven** maar gewoon *headJS* gebruiken!