JavaScript attiva spesso modifiche visive. A volte avviene direttamente tramite manipolazioni dello stile e a volte sono i calcoli a determinare modifiche visive, come la ricerca o l'ordinamento dei dati. Il codice JavaScript con tempistiche errate o che richiede molto tempo è una causa comune di problemi di prestazioni. Dovresti cercare di ridurlo al minimo, se possibile.
JavaScript attiva spesso modifiche visive. A volte avviene direttamente tramite manipolazione dello stile e a volte tramite calcoli che generano modifiche visive, come la ricerca o l'ordinamento dei dati. Il codice JavaScript con tempistiche sbagliate o di lunga esecuzione è una causa comune di problemi di prestazioni. Dovresti cercare di ridurne al minimo l'impatto, se possibile.
Il profiling del rendimento di JavaScript può essere una vera e propria arte, perché il codice JavaScript che scrivi non è assolutamente simile al codice effettivamente eseguito. I browser moderni utilizzano compilatori JIT e ogni sorta di ottimizzazioni e trucchi per provare a offrirti l'esecuzione più rapida possibile e questo cambia notevolmente la dinamica del codice.
Detto questo, però, ci sono alcune cose che puoi fare per aiutare le tue app a eseguire bene JavaScript.
Riepilogo
- Evita di utilizzare setTimeout o setInterval per gli aggiornamenti visivi; utilizza sempre requestAnimationFrame.
- Sposta il codice JavaScript a esecuzione prolungata dal thread principale ai worker web.
- Utilizza le micro-attività per apportare modifiche al DOM in più frame.
- Utilizza la funzionalità Sequenza temporale e il Profiler JavaScript di Chrome DevTools per valutare l'impatto di JavaScript.
Utilizza requestAnimationFrame
per le modifiche visive
Quando sullo schermo si verificano modifiche visive, devi eseguire il tuo lavoro al momento giusto per il browser, ovvero all'inizio del frame. L'unico modo per garantire che il codice JavaScript venga eseguito all'inizio di un frame è utilizzare requestAnimationFrame
.
/**
* If run as a requestAnimationFrame callback, this
* will be run at the start of the frame.
*/
function updateScreen(time) {
// Make visual updates here.
}
requestAnimationFrame(updateScreen);
I framework o i sample potrebbero utilizzare setTimeout
o setInterval
per apportare modifiche visive come le animazioni, ma il problema è che il callback verrà eseguito a un certo punto del frame, possibilmente alla fine, e questo può spesso causare la perdita di un frame, con conseguente balbuzie.
In effetti, jQuery utilizzava setTimeout
per il suo comportamento animate
. È stato modificato per utilizzare
requestAnimationFrame
nella versione 3.
Se utilizzi una versione precedente di jQuery, puoi
applicare una patch per utilizzare requestAnimationFrame
,
che è vivamente consigliato.
Riduci la complessità o utilizza i worker web
JavaScript viene eseguito nel thread principale del browser, insieme ai calcoli degli stili, al layout e, in molti casi, alla pittura. Se il codice JavaScript viene eseguito per molto tempo, bloccherà queste altre attività, potenzialmente causando la perdita di frame.
Devi decidere in modo strategico quando e per quanto tempo eseguire JavaScript. Ad esempio, se stai visualizzando un'animazione come lo scorrimento, dovresti cercare di mantenere il codice JavaScript nell'ordine di 3-4 ms. Se lo fai per più tempo, rischi di impiegare troppo tempo. Se sei in un periodo di inattività, puoi permetterti di essere più rilassato in merito al tempo impiegato.
In molti casi puoi spostare il calcolo puro su Web Worker, se, ad esempio, non richiede l'accesso al DOM. La manipolazione o l'esplorazione dei dati, come l'ordinamento o la ricerca, sono spesso una buona scelta per questo modello, così come il caricamento e la generazione di modelli.
var dataSortWorker = new Worker("sort-worker.js");
dataSortWorker.postMesssage(dataToSort);
// The main thread is now free to continue working on other things...
dataSortWorker.addEventListener('message', function(evt) {
var sortedData = evt.data;
// Update data on screen...
});
Non tutti i lavori possono adattarsi a questo modello: i worker web non hanno accesso al DOM. Se il tuo lavoro deve essere nel thread principale, valuta la possibilità di adottare un approccio batch, in cui suddividi l'attività più grande in micro-attività, ciascuna delle quali non richiede più di qualche millisecondo, ed esegui all'interno di gestori requestAnimationFrame
in ogni frame.
Questo approccio ha conseguenze per l'esperienza utente e l'interfaccia utente e dovrai assicurarti che l'utente sappia che un'attività è in corso, ad esempio utilizzando un indicatore di avanzamento o attività. In ogni caso, questo approccio manterrà libero il thread principale dell'app, aiutandola a rimanere reattiva alle interazioni degli utenti.
Informazioni sulla "tassazione dei frame" di JavaScript
Quando valuti un framework, una libreria o il tuo codice, è importante valutare quanto costa eseguire il codice JavaScript su base frame by frame. Questo è particolarmente importante quando si eseguono animazioni con requisiti di prestazioni elevati, come transizioni o scorrimento.
Il riquadro Rendimento di Chrome DevTools è il modo migliore per misurare il costo di JavaScript. In genere, ricevi record di basso livello come questo:
La sezione Principale fornisce un grafico a forma di fiamma delle chiamate JavaScript, in modo da poter analizzare esattamente quali funzioni sono state chiamate e il tempo impiegato da ciascuna.
Con queste informazioni, puoi valutare l'impatto sul rendimento del codice JavaScript sulla tua applicazione e iniziare a trovare e correggere eventuali hotspot in cui l'esecuzione delle funzioni richiede troppo tempo. Come accennato in precedenza, dovresti cercare di rimuovere il codice JavaScript a esecuzione prolungata o, se non è possibile, spostarlo in un web worker per liberare il thread principale e continuare con altre attività.
Per scoprire come utilizzare il riquadro Rendimento, consulta la sezione Iniziare a analizzare il rendimento in fase di esecuzione.
Evita la microottimizzazione del codice JavaScript
Può essere interessante sapere che il browser può eseguire una versione di un'operazione 100 volte più velocemente di un'altra, ad esempio che la richiesta del offsetTop
di un elemento è più veloce del calcolo del getBoundingClientRect()
, ma è quasi sempre vero che chiamerai funzioni come queste solo un numero limitato di volte per frame, quindi in genere è uno spreco di energie concentrarsi su questo aspetto del rendimento di JavaScript. In genere, risparmierai solo frazioni di millisecondi.
Se stai creando un gioco o un'applicazione con un elevato costo computazionale, probabilmente sei un'eccezione a queste indicazioni, in quanto in genere dovrai adattare molti calcoli in un singolo frame e in questo caso tutto è utile.
In breve, devi stare molto attento alle micro-ottimizzazioni perché in genere non corrispondono al tipo di applicazione che stai creando.