Best practice per migliorare le prestazioni

Questo capitolo tratta molte migliori pratiche JavaScript e jQuery, senza un particolare ordine.
Molte di queste pratiche si basano sulla presentazione jQuery Anti-Patterns for Performance (in inglese) di Paul irlandese.
Salva la lunghezza del loops

In un ciclo, è necessario accedere alla lunghezza di un array ogni volta che viene valutata la condizione; tale valore può essere memorizzato in anticipo in una variabile.
[code lang=”javascript”] var myLength = myArray.length;

for (var i = 0; i < myLength; i++) {
// fare delle cose
}
[/code]

Aggiungere nuovi contenuti fuori da un ciclo
Se si sta inserendo molti elementi nel DOM, fatelo tutti in una volta, non uno per volta.
[code lang=”javascript”] // male
$.each(myArray, function(i, item) {
var newListItem = ‘<li>’ + item + ‘</li>’;
$(‘#ballers’).append(newListItem);
});

// meglio: fare questo
var frag = document.createDocumentFragment();

$.each(myArray, function(i, item) {
var newListItem = ‘<li>’ + item + ‘</li>’;
frag.appendChild(newListItem);
});
$(‘#ballers’)[0].appendChild(frag);

// o questo
var myHtml = ”;

$.each(myArray, function(i, item) {
html += ‘<li>’ + item + ‘</li>’;
});
$(‘#ballers’).html(myHtml);
[/code]

Non Ripetersi
Nessuna ricorrenza; fare le cose una volta e solo una, altrimenti è sbagliato.
[code lang=”javascript”] // MALE
if ($eventfade.data(‘currently’) != ‘showing’) {
$eventfade.stop();
}

if ($eventhover.data(‘currently’) != ‘showing’) {
$eventhover.stop();
}

if ($spans.data(‘currently’) != ‘showing’) {
$spans.stop();
}

// BENE
var $elems = [$eventfade, $eventhover, $spans];
$.each($elems, function(i,elem) {
if (elem.data(‘currently’) != ‘showing’) {
elem.stop();
}
});
[/code]

Attenzione alle funzioni anonime
Non è consigliabile utilizzare abbondantemente le funzioni anonime. Queste sono difficili da eseguire in debug, per la manutenzione, il test e suo riutilizzo. Al suo posto, utilizzare un valore letterale per organizzare e nominare i suoi controllori e le funzioni di retrochiamata (callback).
[code lang=”javascript”] // MALE
$(document).ready(function() {
$(‘#magic’).click(function(e) {
$(‘#yayeffects’).slideUp(function() {
// …
});
});

$(‘#happiness’).load(url + ‘ #unicorns’, function() {
// …
});
});

// MEGLIO
var PI = {
onReady : function() {
$(‘#magic’).click(PI.candyMtn);
$(‘#happiness’).load(PI.url + ‘ #unicorns’, PI.unicornCb);
},

candyMtn : function(e) {
$(‘#yayeffects’).slideUp(PI.slideCb);
},

slideCb : function() { … },

unicornCb : function() { … }
};

$(document).ready(PI.onReady);
[/code]

Ottimizzazione dei selettori
L’ottimizzazione dei selettori è meno importante di una volta, grazie all’implementazione in alcuni browser web document.querySelectorAll(), passando il peso di jQuery verso browser web. Tuttavia, ci sono alcuni consigli da tenere a mente.
Selettori basati sugli ID
È sempre meglio iniziare le selezioni con un ID.
[code lang=”javascript”] // veloce
$(‘#container div.robotarm’);

// super-veloce
$(‘#container’).find(‘div.robotarm’);
[/code]

L’esempio che utilizza $.fn.find è più veloce perché la prima selezione utilizza il motore di selezione interno Sizzle -. Mentre la selezione realizzata unicamente per ID utilizza document.getElementById(), che è estremamente veloce grazie alla è una funzione nativa del browser web.
Specificità
Cercate di essere specifico per il lato destro della selezione e meno specifici per il sinistro.
[code lang=”javascript”] // non ottimizzato
$(‘div.data .gonzalez’);

// ottimizzato
$(‘.data td.gonzalez’);
[/code]

Utilizzare il più possibile tag.classe del lato destro della selezione, e solo tag o .classe a sinistra.

Evitare specificità eccessiva

[code lang=”javascript”] $(‘.data table.attendees td.gonzalez’);

// molto meglio: eliminare il mezzo, se possibile,
$(‘.data td.gonzalez’);
[/code]

La seconda selezione ha prestazioni migliori perché attraversa meno strati per individuare l’elemento.
Evitare il selettore universale
Selezioni dove si specifica implicita o esplicitamente una selezione universale che può essere molto lento.
[code lang=”javascript”] $(‘.buttons > *’); // molto lento
$(‘.buttons’).children(); // molto meglio

$(‘.gender :radio’); // selezione universale implicita
$(‘.gender *:radio’); // stesa cosa, ma in modo esplicito
$(‘.gender input:radio’); // molto meglio
[/code]

Utilizzare la delegazione di Eventi
La delega di eventi permette vincolare un gestore eventi a un elemento contenitore (per esempio, una lista non ordinata) in luogo di molteplici elementi contenuti (per esempio, gli elementi in una lista). jQuery rende rende questo lavoro facile attraverso $.fn.live e $.fn.delegate. Se possibile, si raccomanda utilizzare $.fn.delegate anziché $.fn.live, giacché elimina la necessità di una selezione e il suo contesto esplicito riduce il carico di circa il 80%.

Inoltre, la delegazione di eventi permette di aggiungere nuovi elementi contenitori alla pagina, senza dover vincolare i loro gestori di eventi.

[code lang=”javascript”] // sbagliato (se ci sono molti elementi nella lista)
$(‘li.trigger’).click(handlerFn);

// meglio: delegazione di eventi con $ fn.live.
$(‘li.trigger’).live(‘click’, handlerFn);

// molto meglio:. delegazione di evento con $ fn.delegate
// permette specificare un contesto in modo facile
$(‘#myList’).delegate(‘li.trigger’, ‘click’, handlerFn);
[/code]

Separare elementi per lavorare con loro
Se possibile, evitare la manipolazione del DOM. Per contribuire a questo scopo, dalla versione 1.4 jQuery introduce $.fn.detach il quale permette lavorare con gli elementi del DOM in forma separata per poi inserirli.
[code lang=”javascript”] var $table = $(‘#myTable’);
var $parent = $table.parent();

$table.detach();
// … si aggiungono molte celle alla tabella
$parent.append($table);
[/code]

Utilizzare stili a cascata per modificare il Css tra vari elementi
Se si modifica il CSS in più di 20 elementi con $.fn.css, considerate le modifiche agli stili con l’aggiunta di un tag style. Ciò consentirà di aumentare le prestazioni del 60%.
[code lang=”javascript”] // corretto fino a 20 elementi, lento dopo i 20 elementi
$(‘a.swedberg’).css(‘color’, ‘#asd123’);
$(‘<style type="text/css">a.swedberg { color : #asd123 }</style>’)
.appendTo(‘head’);
[/code]
Utilizzare $.data anziché $.fn.data
Utilizzare $.data in un elemento DOM invece di $.fn.data in una selezione può essere fino a 10 volte più veloce. Prima di farlo, assicuratevi di capire la differenza tra un elemento DOM e una selezione jQuery.
[code lang=”javascript”] // regolare
$(elem).data(key,value);

// 10 volte più veloce
$.data(elem,key,value);
[/code]

Non agire su elementi inesistenti
jQuery non ci dirà se si cerca di eseguire un codice su una selezione vuota – questo verrà eseguito come se nulla fosse. Dipende da noi vedere se la selezione contiene elementi.
[code lang=”javascript”] // SBAGLIATO: il codice esegue tre funzioni
// senza verificare se ci sono
// nella selezione
$(‘#nosuchthing’).slideUp();

// MEGLIO
var $mySelection = $(‘#nosuchthing’);
if ($mySelection.length) { $mySelection.slideUp(); }

// MOLTO MEGLIO: aggiunge una estensione doOnce
jQuery.fn.doOnce = function(func){
this.length && func.apply(this);
return this;
}

$(‘li.cartitems’).doOnce(function(){
// fare qualcosa
});
[/code]

Questo consiglio è particolarmente adatto per i widget jQuery UI, i quali hanno un carico pesante, anche quando la selezione non contiene elementi.
Definizione di variabili
Le variabili possono essere definite in una unica dichiarazione, invece di più volte.
[code lang=”javascript”] // antico
var test = 1;
var test2 = function() { … };
var test3 = test2(test);

// migliore modo
var test = 1,
test2 = function() { … },
test3 = test2(test);
[/code]

Nelle funzioni di autoeseguibili, le definizioni di variabili possono essere passate tutte insieme.
[code lang=”javascript”] (function(foo, bar) { … })(1, 2);
[/code]
Condizionali
[code lang=”javascript”] // antico
if (type == ‘foo’ || type == ‘bar’) { … }

// migliore
if (/^(foo|bar)$/.test(type)) { … }

// ricerca in oggetto letterale
if (({ foo : 1, bar : 1 })[type]) { … }
[/code]

Non trattare jQuery come se fosse una scatola nera
Utilizzare il codice sorgente della libreria come se fosse la sua documentazione – salva il link http://bit.ly/jqsource come marcatore per usarlo come riferimento.