Migliorare le prestazioni della tua app HTML5

Introduzione

HTML5 ci offre ottimi strumenti per migliorare l'aspetto visivo delle applicazioni web. Ciò è particolarmente vero nel campo delle animazioni. Tuttavia, con questo nuovo potere si presentano anche nuove sfide. In realtà queste sfide non sono così nuove e a volte potrebbe avere senso chiedere alla tua vicina di casa, la programmatrice Flash, come ha superato situazioni simili in passato.

In ogni caso, quando lavori nelle animazioni, diventa estremamente importante che gli utenti percepiscano queste animazioni come fluide. Dobbiamo capire che non è possibile creare fluidità delle animazioni semplicemente aumentando i frame al secondo oltre qualsiasi soglia cognitiva. Il nostro cervello, sfortunatamente, è più intelligente di così. Imparerai che 30 frame di animazione al secondo (f/s) reali sono molto meglio di 60 f/s, con solo pochi frame persi al centro. Le persone odiano i fastidi.

Questo articolo cercherà di fornirti gli strumenti e le tecniche necessarie per migliorare l'esperienza sulla tua applicazione.

La strategia

Non vogliamo in alcun modo scoraggiarti dallo sviluppo di fantastiche app HTML5 dalla grafica sorprendente.

Quando ti accorgi che le prestazioni potrebbero essere migliorate, torna qui e scopri come migliorare gli elementi della tua applicazione. Naturalmente, può essere d'aiuto per svolgere subito alcune attività, ma non lasciare mai che ciò ostacola la tua produttività.

Fedeltà visiva++ con HTML5

Accelerazione hardware

L'accelerazione hardware è un traguardo importante per le prestazioni complessive di rendering nel browser. Lo schema generale prevede di trasferire le attività che altrimenti verrebbero calcolate dalla CPU principale alla GPU (Graphics Processing Unit) nell'adattatore grafico del computer. Ciò può generare importanti miglioramenti delle prestazioni e può anche ridurre il consumo di risorse sui dispositivi mobili.

Questi aspetti del documento possono essere accelerati dalla GPU

  • Composizione del layout generale
  • Transizioni CSS3
  • Trasformazioni 3D CSS3
  • Disegno su tela
  • Disegno 3D WebGL

Sebbene l'accelerazione di canvas e WebGL sono funzionalità per scopi speciali che potrebbero non applicarsi alla tua applicazione specifica, i primi tre aspetti possono aiutare praticamente ogni app a diventare più veloce.

Cosa può essere accelerato?

L'accelerazione della GPU funziona spostando le attività ben definite e specifiche su hardware per usi speciali. Lo schema generale prevede che il documento sia suddiviso in più "livelli" invarianti per gli aspetti accelerati della pagina. Il rendering di questi livelli viene eseguito utilizzando la pipeline di rendering tradizionale. La GPU viene quindi utilizzata per comporre i livelli in una singola pagina applicando gli "effetti" che possono essere accelerati al momento. Un possibile risultato è che un oggetto animato sullo schermo non richiede un singolo "relayout" della pagina durante l'animazione.

Ciò che devi dedurre è che devi consentire al motore di rendering di identificare facilmente quando può applicare la sua magia di accelerazione GPU. Considera l'esempio seguente:

Anche se questa operazione funziona, il browser non sa che stai eseguendo un'azione che dovrebbe essere percepita come un'animazione fluida da un essere umano. Considera cosa succede quando ottieni lo stesso aspetto visivo utilizzando le transizioni CSS3:

La modalità di implementazione di questa animazione da parte del browser è completamente nascosta allo sviluppatore. Questo a sua volta significa che il browser è in grado di applicare trucchi come l'accelerazione GPU per raggiungere l'obiettivo definito.

Sono disponibili due flag della riga di comando utili per Chrome che consentono di eseguire il debug dell'accelerazione della GPU:

  1. --show-composited-layer-borders mostra un bordo rosso intorno agli elementi che vengono manipolati a livello di GPU. Ideale per confermare che le manipolazioni avvengono all'interno del livello GPU.
  2. --show-paint-rects tutte le modifiche non GPU vengono visualizzate e viene visualizzato un bordo chiaro intorno a tutte le aree ridipinte. Puoi vedere la procedura di ottimizzazione delle aree di colore del browser.

Safari ha flag di runtime simili descritti qui.

Transizioni CSS3

Le transizioni CSS rendono l'animazione dello stile banale per tutti, ma sono anche una funzionalità di rendimento intelligente. Poiché una transizione CSS è gestita dal browser, la fedeltà dell'animazione può essere notevolmente migliorata e in molti casi può essere accelerata hardware. Attualmente WebKit (Chrome, Safari, iOS) presenta trasformazioni CSS con accelerazione hardware, ma sta arrivando rapidamente su altri browser e piattaforme.

Puoi utilizzare gli eventi transitionEnd per creare combinazioni efficaci di questi, anche se al momento acquisire tutti gli eventi di fine transizione supportati significa guardare webkitTransitionEnd transitionend oTransitionEnd.

Molte librerie hanno ora introdotto API di animazione che sfruttano le transizioni se presenti e utilizzano altrimenti l'animazione in stile DOM standard. scripty2, transizione YUI, jQuery animata avanzata.

Traduttore CSS3

Di sicuro ti sei capitato di animare la posizione x/y di un elemento nella pagina. Probabilmente hai manipolato le proprietà superiore e sinistra dello stile incorporato. Con le trasformazioni 2D, possiamo utilizzare la funzionalità translate() per replicare questo comportamento.

Possiamo combinare questa funzionalità con l'animazione DOM per utilizzare la migliore

<div style="position:relative; height:120px;" class="hwaccel">

  <div style="padding:5px; width:100px; height:100px; background:papayaWhip;
              position:absolute;" id="box">
  </div>
</div>

<script>
document.querySelector('#box').addEventListener('click', moveIt, false);

function moveIt(evt) {
  var elem = evt.target;

  if (Modernizr.csstransforms && Modernizr.csstransitions) {
    // vendor prefixes omitted here for brevity
    elem.style.transition = 'all 3s ease-out';
    elem.style.transform = 'translateX(600px)';

  } else {
    // if an older browser, fall back to jQuery animate
    jQuery(elem).animate({ 'left': '600px'}, 3000);
  }
}
</script>

Utilizziamo Modernizr per testare le trasformazioni 2D CSS e le transizioni CSS e, in questo caso, utilizzeremo la traslazione per spostare la posizione. Se l'animazione viene eseguita utilizzando una transizione, ci sono buone probabilità che il browser possa accelerarla dall'hardware. Per inviare di nuovo al browser la direzione giusta, useremo il "punto elenco CSS magico" riportato sopra.

Se il nostro browser è meno potente, utilizzeremo jQuery per spostare il nostro elemento. Puoi utilizzare il plug-in polyfill jQuery Transform di Louis-Remi Babe per automatizzare tutto.

window.requestAnimationFrame

requestAnimationFrame è stato introdotto da Mozilla e iterato da WebKit con l'obiettivo di fornirti un'API nativa per l'esecuzione di animazioni, che siano basate su DOM/CSS oppure su <canvas> o WebGL. Il browser può ottimizzare insieme le animazioni contemporanee in un unico ciclo di ripetizione del flusso e ricolorazione, ottenendo un'animazione più fedele. Ad esempio, animazioni basate su JS sincronizzate con transizioni CSS o file SMIL SVG. Inoltre, se esegui il loop dell'animazione in una scheda non visibile, il browser non lo manterrà in esecuzione, il che comporta un minore utilizzo di CPU, GPU e memoria, con un conseguente incremento della durata della batteria.

Per ulteriori dettagli su come e perché utilizzare requestAnimationFrame, leggi l'articolo di Paul Ireland requestAnimationFrame per l'animazione intelligente.

Profilazione

Quando scopri che la velocità della tua applicazione può essere migliorata, è il momento di analizzare la profilazione per scoprire dove le ottimizzazioni potrebbero generare i maggiori benefici. Le ottimizzazioni hanno spesso un impatto negativo sulla manutenibilità del codice sorgente e pertanto dovrebbero essere applicate solo se necessario. La profilazione indica quali parti del tuo codice produrrebbero i maggiori benefici in caso di miglioramento delle prestazioni.

Profilazione JavaScript

I profiler JavaScript offrono una panoramica delle prestazioni della tua applicazione a livello di funzione JavaScript misurando il tempo necessario per eseguire ogni singola funzione dall'inizio alla fine.

Il tempo lordo di esecuzione di una funzione corrisponde al tempo complessivo necessario per eseguirla dall'alto verso il basso. Il tempo di esecuzione netto corrisponde al tempo di esecuzione lordo meno il tempo necessario per eseguire le funzioni richiamate dalla funzione.

Alcune funzioni vengono chiamate più spesso di altre. I profiler di solito forniscono il tempo necessario per l'esecuzione di tutte le chiamate, nonché il tempo medio, minimo e massimo di esecuzione.

Per ulteriori dettagli, consulta la documentazione di Chrome Dev Tools sulla profilazione.

Il DOM

Le prestazioni di JavaScript hanno una forte influenza sulla fluidità e sulla reattività della tua applicazione. È importante comprendere che, anche se i profiler JavaScript misurano il tempo di esecuzione di JavaScript, anche indirettamente misurano il tempo speso per le operazioni DOM. Queste operazioni DOM sono spesso al centro dei problemi di prestazioni.

function drawArray(array) {
  for(var i = 0; i < array.length; i++) {
    document.getElementById('test').innerHTML += array[i]; // No good :(
  }
}

Ad esempio, nel codice sopra indicato non viene dedicato quasi tempo all'esecuzione del codice JavaScript effettivo. È comunque molto probabile che la funzione trainArray venga visualizzata nei profili poiché interagisce con il DOM in modo molto sprecato.

Suggerimenti utili

Funzioni anonime

Le funzioni anonime non sono facili da profilare perché di per sé non hanno un nome con cui potrebbero essere visualizzate nel profiler. Puoi risolvere il problema in due modi:

$('.stuff').each(function() { ... });

riscrivi in:

$('.stuff').each(function workOnStuff() { ... });

Non è risaputo che JavaScript supporti le espressioni di funzioni di denominazione. In questo modo verranno visualizzati perfettamente nel profiler. Si è verificato un problema con questa soluzione: l'espressione con nome inserisce in realtà il nome della funzione nell'ambito lessicale corrente. Questa operazione potrebbe danneggiare altri simboli, quindi fai attenzione.

Profilazione delle funzioni lunghe

Immagina di avere una funzione lunga e sospetti che una sua piccola parte possa essere il motivo dei tuoi problemi di prestazioni. Esistono due modi per scoprire quale parte è il problema:

  1. Il metodo corretto: esegui il refactoring del codice per non includere funzioni lunghe.
  2. Il metodo dannoso per fare le cose: aggiungere al codice istruzioni sotto forma di funzioni autochiamate con nome. Se fai un po' di attenzione, la semantica non cambia e parti della funzione vengono visualizzate come funzioni individuali nel profiler: js function myLongFunction() { ... (function doAPartOfTheWork() { ... })(); ... } Non dimenticare di rimuovere queste funzioni aggiuntive dopo aver completato la profilazione o persino di utilizzarle come punto di partenza per il refactoring del codice.

Profilazione DOM

Gli ultimi strumenti di sviluppo di Chrome Web Inspector contengono la nuova "Visualizzazione cronologia", che mostra una sequenza temporale delle azioni di basso livello eseguite dal browser. Puoi utilizzare queste informazioni per ottimizzare le operazioni DOM. Dovresti cercare di ridurre il numero di "azioni" che il browser deve eseguire durante l'esecuzione del codice.

La visualizzazione cronologica può creare un'immensa quantità di informazioni. Pertanto, cerca di creare scenari di test minimi da eseguire in modo indipendente.

Profilazione DOM

L'immagine riportata sopra mostra l'output della visualizzazione cronologica di uno script molto semplice. Il riquadro di sinistra mostra le operazioni eseguite dal browser in ordine cronologico, mentre la sequenza temporale nel riquadro di destra mostra il tempo effettivo utilizzato da una singola operazione.

Maggiori informazioni sulla visualizzazione cronologica. Uno strumento alternativo per la profilazione in Internet Explorer è DynaTrace Ajax Edition.

Strategie di profilazione

Individuare gli aspetti

Quando vuoi profilare la tua applicazione, cerca di individuare gli aspetti della sua funzionalità che potrebbero attivare la lentezza il più possibile. Quindi prova a eseguire un'esecuzione del profilo che esegua solo le parti del codice pertinenti a questi aspetti dell'applicazione. In questo modo, i dati di profilazione saranno più facili da interpretare perché non sono mescolati con percorsi di codice non correlati al problema effettivo. Ecco alcuni buoni esempi di singoli aspetti della tua applicazione:

  1. Tempo di avvio (attiva il profiler, ricarica l'applicazione, attendi il completamento dell'inizializzazione, arresta il profiler).
  2. Fai clic su un pulsante e poi sull'animazione successiva (avvia profiler, fai clic sul pulsante, attendi il completamento dell'animazione, interrompi profiler).
Profilazione delle GUI

Eseguire solo la parte giusta dell'applicazione può essere più difficile in un programma GUI rispetto a quando ottimizzi, ad esempio, il ray tracer del tuo motore 3D. Ad esempio, quando vuoi profilare gli eventi che si verificano quando fai clic su un pulsante, potresti attivare eventi mouseover non correlati che rendano i tuoi risultati meno definitivi. Cerca di evitarlo :)

Interfaccia di programmazione

C'è anche un'interfaccia di programmazione per attivare il debugger. Questo consente un controllo preciso sull'inizio e sulla fine della profilazione.

Avvia una profilazione con:

console.profile()

Interrompi profilazione con:

console.profileEnd()

Ripetibilità

Quando esegui la profilazione, assicurati di poter riprodurre effettivamente i risultati. Solo così sarai in grado di capire se le tue ottimizzazioni hanno effettivamente migliorato le cose. Anche la profilazione a livello di funzione viene eseguita nel contesto dell'intero computer. Non è una scienza esatta. Le esecuzioni dei singoli profili potrebbero essere influenzate da molti altri fattori che avvengono sul computer:

  1. Un timer non correlato nella tua applicazione che si attiva mentre misuri qualcos'altro.
  2. Il garbage collection fa il suo lavoro.
  3. Un'altra scheda del browser lavora incessantemente nello stesso thread operativo.
  4. Un altro programma sul computer che consuma la CPU, rallentando così l'applicazione.
  5. Cambiamenti improvvisi del campo gravitazionale della Terra.

Ha anche senso eseguire lo stesso percorso di codice più volte in una singola sessione di profilazione. In questo modo si riduce l'influenza dei fattori sopra indicati e le parti lente potrebbero risaltare ancora più chiaramente.

Misura, migliora, misura

Quando hai identificato un punto lento nel tuo programma, prova a pensare a dei modi per migliorare il comportamento di esecuzione. Dopo aver modificato il codice, riposiziona il profilo. Se il risultato ti soddisfa, continua così. Se non noti alcun miglioramento, probabilmente dovresti annullare la modifica e non lasciarla "perché non può essere influenzata".

Strategie di ottimizzazione

Riduci al minimo l'interazione con il DOM

Un tema comune per migliorare la velocità delle applicazioni client web è ridurre al minimo l'interazione DOM. Mentre la velocità dei motori JavaScript è aumentata di un ordine di grandezza, l'accesso al DOM non è diventato più veloce con la stessa velocità. Ciò è anche per motivi molto pratici che non accadranno mai (cose come il layout e il disegno su uno schermo richiedono tempo).

Memorizzazione nella cache dei nodi DOM

Ogni volta che recuperi un nodo o un elenco di nodi dal DOM, prova a pensare se potresti essere in grado di riutilizzarli in un calcolo successivo (o anche solo nella iterazione del loop successiva). Finché non aggiungi o elimini effettivamente i nodi nell'area pertinente, spesso è questo il caso.

Prima:

function getElements() {
  return $('.my-class');
}

Dopo:

var cachedElements;
function getElements() {
  if (cachedElements) {
    return cachedElements;
  }
  cachedElements = $('.my-class');
  return cachedElements;
}

Valori degli attributi cache

Allo stesso modo in cui puoi memorizzare nella cache i nodi DOM, puoi anche memorizzare nella cache i valori degli attributi. Immagina di animare un attributo dello stile di un nodo. Se sai che tu (come in quella parte del codice) sei l'unico in grado di toccare quell'attributo, puoi memorizzare nella cache l'ultimo valore di ogni iterazione in modo da non doverlo leggere ripetutamente.

Prima:

setInterval(function() {
  var ele = $('#element');
  var left = parseInt(ele.css('left'), 10);
  ele.css('left', (left + 5) + 'px');
}, 1000 / 30);

Dopo: js var ele = $('#element'); var left = parseInt(ele.css('left'), 10); setInterval(function() { left += 5; ele.css('left', left + 'px'); }, 1000 / 30);

Sposta la manipolazione del DOM fuori dai loop

I loop sono spesso punti critici per l'ottimizzazione. Prova a pensare a dei modi per disaccoppiare il calcolo dei numeri reali per lavorare con il DOM. Spesso è possibile eseguire un calcolo e poi applicare tutti i risultati in una volta sola.

Prima:

document.getElementById('target').innerHTML = '';
for(var i = 0; i < array.length; i++) {
  var val = doSomething(array[i]);
  document.getElementById('target').innerHTML += val;
}

Dopo:

var stringBuilder = [];
for(var i = 0; i < array.length; i++) {
  var val = doSomething(array[i]);
  stringBuilder.push(val);
}
document.getElementById('target').innerHTML = stringBuilder.join('');

Riscaldamenti e adattamenti di flusso

Come discusso in precedenza, l'accesso al DOM è relativamente lento. Diventa molto lento quando il codice legge un valore che deve essere ricalcolato perché di recente il codice ha modificato un elemento correlato nel DOM. Pertanto, si dovrebbe evitare di confondere l'accesso in lettura e scrittura al DOM. Idealmente, il tuo codice dovrebbe essere sempre raggruppato in due fasi:

  • Fase 1: leggi i valori DOM necessari per il codice
  • Fase 2: modifica del DOM

Cerca di non programmare un pattern come:

  • Fase 1: lettura dei valori DOM
  • Fase 2: modifica del DOM
  • Fase 3: scopri di più
  • Fase 4: modifica il DOM altrove.

Prima:

function paintSlow() {
  var left1 = $('#thing1').css('left');
  $('#otherThing1').css('left', left);
  var left2 = $('#thing2').css('left');
  $('#otherThing2').css('left', left);
}

Dopo:

function paintFast() {
  var left1 = $('#thing1').css('left');
  var left2 = $('#thing2').css('left');
  $('#otherThing1').css('left', left);
  $('#otherThing2').css('left', left);
}

Questo consiglio è da considerare per azioni che si verificano all'interno di un contesto di esecuzione JavaScript. (ad esempio, all'interno di un gestore di eventi, all'interno di un gestore di intervalli o quando si gestisce una risposta ajax).

L'esecuzione della funzione paintSlow() dall'alto crea questa immagine:

paintSlow()

Il passaggio all'implementazione più rapida restituisce questa immagine:

Implementazione più rapida

Queste immagini mostrano che il riordinamento delle modalità di accesso del codice al DOM può migliorare notevolmente le prestazioni di rendering. In questo caso, il codice originale deve ricalcolare gli stili e il layout della pagina due volte per ottenere lo stesso risultato. Un'ottimizzazione simile può essere applicata praticamente a tutto il codice del mondo reale e produce risultati davvero sorprendenti.

Scopri di più: Rendering: repaint, reflow/relayout, restyle di Stoyan Stefanov

Riadattamenti e loop di eventi

L'esecuzione di JavaScript nel browser segue un modello "Event Loop". Per impostazione predefinita, il browser è in stato "inattivo". Questo stato può essere interrotto da eventi derivanti dalle interazioni degli utenti, ad esempio timer JavaScript o callback Ajax. Ogni volta che un elemento di JavaScript viene eseguito in un punto di interruzione del genere, il browser attende che venga completato fino a quando non ridipinge lo schermo (potrebbero verificarsi eccezioni per codice JavaScript a esecuzione estremamente lunga o in casi come caselle di avviso che interrompono effettivamente l'esecuzione di JavaScript).

Conseguenze

  1. Se l'esecuzione dei cicli di animazione JavaScript richiede più di 1/30 di secondo, non potrai creare animazioni fluide perché il browser non verrà ridipinto durante l'esecuzione di JS. Quando prevedi di gestire anche gli eventi utente, devi essere molto più veloce.
  2. A volte è utile ritardare alcune azioni JavaScript. Esempio: setTimeout(function() { ... }, 0) Questo indica al browser di eseguire il callback non appena il loop di eventi sarà di nuovo inattivo (in pratica alcuni browser attenderanno almeno 10 ms). Devi tenere presente che in questo modo verranno creati due cicli di esecuzione JavaScript molto vicini nel tempo. Entrambe potrebbero attivare una ricolorazione dello schermo che potrebbe raddoppiare il tempo complessivo impiegato per colorare. L'attivazione effettiva di due visualizzazioni dipende dall'euristica nel browser.

Versione normale:

function paintFast() {
  var height1 = $('#thing1').css('height');
  var height2 = $('#thing2').css('height');
  $('#otherThing1').css('height', '20px');
  $('#otherThing2').css('height', '20px');
}
Riadattamenti e loop di eventi

Aggiungiamo un po' di ritardo:

function paintALittleLater() {
  var height1 = $('#thing1').css('height');
  var height2 = $('#thing2').css('height');
  $('#otherThing1').css('height', '20px');
  setTimeout(function() {
    $('#otherThing2').css('height', '20px');
  }, 10)
}
Ritardo

La versione ritardata mostra che il browser viene visualizzato due volte, anche se le due modifiche alla pagina sono solo 1/100 di secondo.

Inizializzazione lazy

Gli utenti vogliono app web che si carichino rapidamente e siano reattive. Tuttavia, gli utenti hanno soglie diverse per ciò che percepiscono come lento a seconda dell'azione che eseguono. Ad esempio, un'app non dovrebbe mai eseguire molti calcoli su un evento mouseover perché ciò potrebbe creare un'esperienza utente negativa mentre l'utente continua a spostare il mouse. Tuttavia, gli utenti sono abituati ad accettare un leggero ritardo dopo aver fatto clic su un pulsante.

Potrebbe quindi essere opportuno spostare il codice di inizializzazione in modo che venga eseguito il più tardi possibile (ad esempio, quando l'utente fa clic su un pulsante che attiva un particolare componente della tua applicazione).

Prima del: js var things = $('.ele > .other * div.className'); $('#button').click(function() { things.show() });

Dopo: js $('#button').click(function() { $('.ele > .other * div.className').show() });

Delega evento

La distribuzione dei gestori di eventi in una pagina potrebbe richiedere un tempo relativamente lungo e può essere noiosa anche una volta sostituiti dinamicamente gli elementi, che a sua volta richiede di ricollegare i gestori di eventi ai nuovi elementi.

In questo caso la soluzione consiste nell'utilizzare una tecnica chiamata delega di eventi. Invece di collegare gestori di eventi singoli agli elementi, la natura bubbling di molti eventi del browser viene utilizzata collegando effettivamente il gestore di eventi a un nodo padre e controllando il nodo target dell'evento per vedere se l'evento è di interesse.

In jQuery questo può essere facilmente espresso come:

$('#parentNode').delegate('.button', 'click', function() { ... });

Quando non utilizzare la delega eventi

A volte può essere vero il contrario: stai utilizzando la delega di eventi e hai un problema di rendimento. Sostanzialmente, la delega degli eventi consente tempi di inizializzazione a complessità costante. Tuttavia, il prezzo per verificare se un evento è di interesse deve essere pagato per ogni chiamata a quell'evento. Questa opzione potrebbe rivelarsi costosa, soprattutto per eventi che si verificano spesso come "mouseover" o persino "mousemove".

Problemi e soluzioni tipici

Le cose che faccio in $(document).ready richiedono molto tempo

Consiglio personale di Malte: Non fare mai nulla in $(document).ready. Prova a inviare il documento nella sua forma finale. Ok, puoi registrare i listener di eventi, ma solo utilizzando id-selector e/o utilizzando la delega di eventi. Per eventi costosi come "mousemove", posticipa la registrazione finché non sono necessari (evento di passaggio del mouse sull'elemento pertinente).

E se hai davvero bisogno di eseguire operazioni come fare una richiesta Ajax per ottenere dati effettivi, mostra una bella animazione; potresti voler includere l'animazione come URI dei dati se è una GIF animata o simile.

Da quando ho aggiunto un filmato Flash alla pagina, tutto è molto lento

L'aggiunta di Flash a una pagina rallenta sempre un po' il rendering perché il layout finale della finestra deve essere "negoziato" tra il browser e il plug-in Flash. Se non riesci a evitare del tutto l'inserimento di Flash nelle tue pagine, assicurati di impostare il parametro Flash "wmode" sul valore "window" (valore predefinito). Verrà disattivata la possibilità di utilizzare elementi HTML e Flash compositi. Non potrai visualizzare un elemento HTML sopra il filmato Flash e il filmato Flash non potrà essere trasparente. Questo potrebbe essere un disagio, ma migliorerà notevolmente il tuo rendimento. Ad esempio, guarda il modo in cui youtube.com evita di inserire dei livelli sopra il video player principale.

Sto salvando elementi in localStorage, ora la mia applicazione si interrompe

La scrittura su localStorage è un'operazione sincrona che prevede l'avvio del disco rigido. Non vuoi mai eseguire operazioni sincrone a "lunga esecuzione" durante le animazioni. Sposta l'accesso a localStorage in un punto del codice in cui sei sicuro che l'utente sia inattivo e che non siano in corso animazioni.

La profilazione dei punti a un selettore jQuery è molto lenta

Innanzitutto devi assicurarti che il selettore possa essere eseguito tramite document.querySelectorAll. Puoi verificarlo nella console JavaScript. In caso di eccezione, riscrivi il selettore in modo che non utilizzi un'estensione speciale del framework JavaScript. Il selettore nei browser moderni verrà accelerato di un ordine di grandezza.

Se il problema persiste o se vuoi essere veloce nei browser moderni, segui queste linee guida:

  • Fornisci informazioni il più specifiche possibile sul lato destro del selettore.
  • Utilizza un nome di tag che non utilizzi spesso come parte più a destra del selettore.
  • Se il problema persiste, prova a riscrivere le informazioni così da poter usare un selettore di ID.

Tutte queste manipolazioni del DOM richiedono molto tempo

L'inserimento, la rimozione e l'aggiornamento di un gruppo di nodi DOM possono essere molto lenti. In genere, questo può essere ottimizzato generando una stringa di codice HTML di grandi dimensioni e utilizzando domNode.innerHTML = newHTML per sostituire i contenuti precedenti. Tieni presente che ciò potrebbe essere molto negativo per la gestibilità e potrebbe creare link di memoria in IE, quindi fai attenzione.

Un altro problema comune è che il codice di inizializzazione crea molto codice HTML. Ad esempio, un plug-in jQuery che trasforma una casella di selezione in un gruppo di div, perché è quello che il design volevano per l'ignoranza delle best practice per l'esperienza utente. Se vuoi davvero che la tua pagina sia veloce, non farlo mai. Consegna invece tutto il markup dal lato server nella sua forma finale. Anche in questo caso ci sono molti problemi, quindi cerca di capire se la velocità vale il compromesso.

Strumenti

  1. JSPerf - Esegui il benchmark di piccoli snippet di JavaScript
  2. Firebug - Per la profilazione in Firefox
  3. Strumenti per sviluppatori di Google Chrome (disponibile come Web Inspector in Safari)
  4. DOM Monster: per ottimizzare le prestazioni del DOM
  5. DynaTrace Ajax Edition - Per ottimizzazioni di profilazione e colorazione in Internet Explorer

Per approfondire

  1. Velocità Google
  2. Paul Ireland sulle prestazioni di jQuery
  3. Prestazioni JavaScript estreme (presentazione di slide)