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.
var myLength = myArray.length;

for (var i = 0; i < myLength; i++) {
    // fare delle cose
}
Aggiungere nuovi contenuti fuori da un ciclo
Se si sta inserendo molti elementi nel DOM, fatelo tutti in una volta, non uno per volta.
// 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);
Non Ripetersi
Nessuna ricorrenza; fare le cose una volta e solo una, altrimenti è sbagliato.
// 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();
    }
});
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).
// 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);
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.
// veloce
$('#container div.robotarm');

// super-veloce
$('#container').find('div.robotarm');
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.
// non ottimizzato
$('div.data .gonzalez');

// ottimizzato
$('.data td.gonzalez');
Utilizzare il più possibile tag.classe del lato destro della selezione, e solo tag o .classe a sinistra.

Evitare specificità eccessiva

$('.data table.attendees td.gonzalez');

// molto meglio: eliminare il mezzo, se possibile,
$('.data td.gonzalez');
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.
$('.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
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.

// 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);
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.
var $table = $('#myTable');
var $parent = $table.parent();

$table.detach();
// ... si aggiungono molte celle alla tabella
$parent.append($table);
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%.
// 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');
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.
// regolare
$(elem).data(key,value);

// 10 volte più veloce
$.data(elem,key,value);
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.
// 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
});
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.
// antico
var test = 1;
var test2 = function() { ... };
var test3 = test2(test);

// migliore modo
var test = 1,
    test2 = function() { ... },
    test3 = test2(test);
Nelle funzioni di autoeseguibili, le definizioni di variabili possono essere passate tutte insieme.
(function(foo, bar) { ... })(1, 2);
Condizionali
// antico
if (type == 'foo' || type == 'bar') { ... }

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

// ricerca in oggetto letterale
if (({ foo : 1, bar : 1 })[type]) { ... }
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.