Ottimizza First Input Delay

Come rispondere più velocemente alle interazioni degli utenti.

Ho fatto clic, ma non è successo nulla. Perché non riesco a interagire con questa pagina? 😢

First Contentful Paint (FCP) e Largest Contentful Paint (LCP) sono due metriche che misurano il tempo necessario per la visualizzazione visiva dei contenuti (ovvero la visualizzazione) su una pagina. Sebbene siano importanti, i tempi di colorazione non acquisiscono la reattività di caricamento, ovvero la velocità con cui una pagina risponde all'interazione dell'utente.

First Input Delay (FID) è una metrica Segnali web essenziali che acquisisce la prima impressione di un utente relativa all'interattività e alla reattività di un sito. Misura il tempo tra la prima interazione di un utente con una pagina e il momento in cui il browser è effettivamente in grado di rispondere a quell'interazione. Il FID è una metrica di campo e non può essere simulata in un ambiente di lab. Per misurare il ritardo di risposta, è necessaria un'interazione reale dell'utente.

I valori di Fiducia buona sono 2,5 secondi, quelli scarsi sono maggiori di 4,0 secondi e tutto il resto deve essere migliorato

Per prevedere il FID nel lab, ti consigliamo il tempo di blocco totale (TBT). Misurano cose diverse, ma i miglioramenti di TBT di solito corrispondono a quelli di FID.

La causa principale di un FID scadente è l'esecuzione di JavaScript pesante. L'ottimizzazione del modo in cui JavaScript analizza, compila ed esegue le pagine web riduce direttamente il FID.

Esecuzione di JavaScript intensivo

Il browser non può rispondere alla maggior parte degli input utente durante l'esecuzione di JavaScript nel thread principale. In altre parole, il browser non può rispondere alle interazioni dell'utente mentre il thread principale è occupato. Per migliorare questa situazione:

Suddividi attività lunghe

Se hai già tentato di ridurre la quantità di JavaScript caricato su una singola pagina, può essere utile suddividere il codice a lunga esecuzione in attività più piccole e asincrone.

Le attività lunghe sono periodi di esecuzione di JavaScript in cui gli utenti potrebbero rilevare che la tua UI non risponde. Qualsiasi frammento di codice che blocca il thread principale per almeno 50 ms può essere caratterizzato come attività lunga. Le attività lunghe sono un segnale di potenziale gonfiore JavaScript (caricamento ed esecuzione più lunghi di quanto un utente potrebbe aver bisogno in questo momento). Suddividere le attività lunghe può ridurre il ritardo di input sul tuo sito.

Attività lunghe in Chrome DevTools
Chrome DevTools visualizza le attività lunghe nel riquadro Prestazioni

Il FID dovrebbe migliorare notevolmente con l'adozione di best practice come la suddivisione del codice e la suddivisione delle attività lunghe. Sebbene TBT non sia una metrica sul campo, è utile per verificare i progressi compiuti nel migliorare sia il tempo all'interattività (TTI) che il FID.

Ottimizza la tua pagina per la preparazione all'interazione

Esistono diverse cause comuni di punteggi FID e TBT scarsi nelle app web che fanno molto affidamento su JavaScript:

L'esecuzione di script proprietari può ritardare la preparazione all'interazione

  • Il gonfiamento delle dimensioni di JavaScript, i tempi di esecuzione gravosi e la suddivisione in blocchi inefficienti possono rallentare il tempo necessario a una pagina in grado di rispondere all'input utente e influire su FID, TBT e TTI. Il caricamento progressivo del codice e delle funzionalità può aiutarti a distribuire questo esercizio e migliorare la prontezza dell'interazione.
  • È possibile che le app visualizzate lato server appaiano rapidamente come pixel visualizzati sullo schermo, ma fai attenzione alle interazioni degli utenti che vengono bloccate da esecuzioni di script di grandi dimensioni (ad esempio, reidratazione per collegare i listener di eventi). Questa operazione può richiedere diverse centinaia di millisecondi, a volte anche secondi, se usi la suddivisione del codice basata su route. Valuta la possibilità di spostare più logica lato server o di generare più contenuti in modo statico durante la creazione.

Di seguito sono riportati i punteggi TBT prima e dopo l'ottimizzazione del caricamento degli script proprietari per un'applicazione. Spostando il costoso caricamento (e l'esecuzione) degli script per un componente non essenziale dal percorso critico, gli utenti sono riusciti a interagire con la pagina molto prima.

Miglioramenti del punteggio TBT in Lighthouse dopo l'ottimizzazione dello script proprietario.

Il recupero dei dati può influire su molti aspetti della preparazione all'interazione

  • L'attesa di una struttura a cascata di recuperi a cascata (ad esempio il recupero di JavaScript e dei dati per i componenti) può influire sulla latenza dell'interazione. Cerca di ridurre al minimo la dipendenza dai recuperi dei dati a cascata.
  • Datastore in linea di grandi dimensioni possono inviare al mittente i tempi di analisi HTML e influire sulle metriche di visualizzazione e interazione. Cerca di ridurre al minimo la quantità di dati da post-elaborare sul lato client.

Anche l'esecuzione di script di terze parti può ritardare la latenza dell'interazione

  • Molti siti includono tag e dati di analisi di terze parti che possono mantenere occupata la rete e far sì che il thread principale non risponda periodicamente, con ripercussioni sulla latenza dell'interazione. Esplora il caricamento on demand del codice di terze parti (ad esempio, potresti non caricare gli annunci below the fold finché non viene fatto scorrere più vicino all'area visibile).
  • In alcuni casi, gli script di terze parti possono prerilasciare quelli proprietari in termini di priorità e larghezza di banda nel thread principale, ritardando anche il momento in cui una pagina sarà pronta per l'interazione. Prova prima a dare la priorità al caricamento di ciò che ritieni offra il massimo valore agli utenti.

Utilizzare un web worker

Il blocco del thread principale è una delle cause principali del ritardo di input. I web worker consentono di eseguire JavaScript su un thread in background. Lo spostamento delle operazioni non UI in un thread worker separato può ridurre i tempi di blocco del thread principale e, di conseguenza, migliorare il FID.

Prendi in considerazione l'utilizzo delle seguenti librerie per semplificare l'utilizzo dei web worker sul tuo sito:

  • Comlink: una libreria helper che astrae postMessage e ne semplifica l'utilizzo
  • Workway: un esportatore di web worker per uso generico
  • Workerize: sposta un modulo in un web worker

Ridurre il tempo di esecuzione di JavaScript

Limitare la quantità di JavaScript nella pagina riduce il tempo necessario al browser per eseguire il codice JavaScript. Ciò consente di velocizzare la velocità con cui il browser può iniziare a rispondere a qualsiasi interazione dell'utente.

Per ridurre la quantità di JavaScript eseguito nella tua pagina:

  • Rimanda JavaScript inutilizzato
  • Riduci al minimo i polyfill non utilizzati

Rimanda JavaScript inutilizzato

Per impostazione predefinita, tutto JavaScript blocca la visualizzazione. Quando il browser rileva un tag script che rimanda a un file JavaScript esterno, deve sospendere le operazioni eseguite e scaricare, analizzare, compilare ed eseguire il codice JavaScript. Dovresti quindi caricare solo il codice necessario per la pagina o per rispondere all'input dell'utente.

La scheda Copertura di Chrome DevTools può indicare la quantità di JavaScript non utilizzata nella tua pagina web.

La scheda Copertura.

Per ridurre il numero di JavaScript inutilizzato:

  • Suddividi il tuo bundle in più blocchi
  • Rimanda qualsiasi codice JavaScript non critico, inclusi script di terze parti, utilizzando async o defer

La suddivisione del codice è il concetto di suddivisione di un singolo bundle JavaScript di grandi dimensioni in blocchi più piccoli che possono essere caricati in modo condizionale (detto anche caricamento lento). La maggior parte dei browser più recenti supporta la sintassi di importazione dinamica, che consente il recupero dei moduli on demand:

import('module.js').then((module) => {
  // Do something with the module.
});

L'importazione dinamica di JavaScript in determinate interazioni dell'utente (ad esempio la modifica di una route o la visualizzazione di una finestra modale) garantirà che il codice non utilizzato per il caricamento iniziale della pagina venga recuperato solo quando necessario.

Oltre al supporto generale del browser, la sintassi di importazione dinamica può essere utilizzata in molti sistemi di build diversi.

  • Se utilizzi webpack, Rollup o Parcel come bundler di moduli, sfrutta il loro supporto per l'importazione dinamica.
  • I framework lato client, come React, Angular e Vue, forniscono astrazioni per semplificare il caricamento lento a livello di componente.

A parte la suddivisione del codice, utilizza sempre asinc o differisce per gli script che non sono necessari per i contenuti above the fold o con percorsi critici.

<script defer src="…"></script>
<script async src="…"></script>

A meno che non ci sia un motivo specifico, tutti gli script di terze parti devono essere caricati con defer o async per impostazione predefinita.

Riduci al minimo i polyfill non utilizzati

Se crei il codice utilizzando la sintassi JavaScript moderna e fai riferimento alle API dei browser moderni, dovrai eseguirne il transpile e includere i polyfill in modo che funzioni nei browser meno recenti.

Uno dei principali problemi di prestazioni dell'inclusione di polyfill e codice trapuntato nel tuo sito è che i browser più recenti non dovrebbero doverlo scaricare se non ne hanno bisogno. Per ridurre le dimensioni JavaScript della tua applicazione, riduci al minimo i polyfill inutilizzati e limita il loro utilizzo agli ambienti in cui sono necessari.

Per ottimizzare l'utilizzo del polyfill sul tuo sito:

  • Se utilizzi Babel come transpiler, utilizza @babel/preset-env per includere solo i polyfill necessari per i browser che intendi scegliere come target. Per Babel 7.9, abilita l'opzione bugfixes per ridurre ulteriormente i polyfill non necessari
  • Utilizza il pattern module/nomodule per pubblicare due bundle separati (@babel/preset-env lo supporta anche tramite target.esmodules)

    <script type="module" src="modern.js"></script>
    <script nomodule src="legacy.js" defer></script>
    

    Molte funzionalità ECMAScript più recenti compilate con Babel sono già supportate in ambienti che supportano i moduli JavaScript. In questo modo, semplifichi la procedura e ti assicuri che venga utilizzato solo il codice transpilato per i browser che ne hanno effettivamente bisogno.

Strumenti per sviluppatori

Sono disponibili diversi strumenti per misurare il FID ed eseguirne il debug:

Grazie a Philip Walton, Kayce Basques, Ilya Grigorik e Annie Sullivan per le loro recensioni.