Skip to main content

Rendo il web più veloce e più usabile

Presentazione di yieldy-for-loop: un pacchetto npm per mantenere i loop non bloccanti (e la UI fluida)

Se avete mai dovuto elaborare migliaia (o milioni) di elementi in JavaScript, avrete probabilmente sperimentato quel fastidioso lag o blocco dell'interfaccia utente. Può accadere quando si eseguono cicli intensivi sul thread principale, bloccando gli aggiornamenti dell'interfaccia. Per affrontare questo problema, ho creato un pacchetto npm chiamato yieldy-for-loop. Questa piccola utility vi aiuta a suddividere cicli di grandi dimensioni in blocchi, cedendo periodicamente il controllo al browser per far sì che la vostra applicazione rimanga reattiva.

yieldy-for-loop su npm
yieldy-for-loop sul sito web di npm

Contesto #

I long task sono un comune collo di bottiglia per le prestazioni nelle applicazioni front-end. Quando il thread principale è occupato a eseguire cicli di grandi dimensioni, i browser non possono aggiornare l'interfaccia utente e gli utenti potrebbero notare una mancanza di reattività o uno scrolling a scatti. Ispirato dall'articolo “Breaking up with long tasks, or how I learned to group loops and wield the yield” (PerfPlanet 2024), volevo una funzione semplice e riutilizzabile che potesse:

  1. Suddividere cicli di grandi dimensioni in lotti (batch) più piccoli.
  2. Cedere il controllo al browser (yield) dopo ogni lotto, dando al motore di rendering la possibilità di aggiornare la pagina e all'utente quella di interagire.
  3. Adattarsi a seconda che il documento sia visibile o nascosto, dato che il lavoro svolto in una scheda in background (nascosta) può essere deprioritarizzato o addirittura sospeso in molti browser.

Così è nato yieldy-for-loop.

Cosa fa #

Installazione #

npm install yieldy-for-loop

Esempio di utilizzo #

import yieldyForLoop from 'yieldy-for-loop';

const items = Array.from({ length: 100000 }, (_, i) => i);

function processItem(item) {
  // La vostra logica di elaborazione pesante
  console.log('Processing item:', item);
}

(async function main() {
  console.log('Starting yieldy loop...');
  
  await yieldyForLoop(items, processItem, {
    fps: 30,              // Punta a circa 30 fotogrammi al secondo
    hiddenThreshold: 500, // Soglia di yield (in ms) quando la scheda è nascosta
  });
  
  console.log('All items processed without blocking the UI!');
})();

Come funziona #

  1. Calcolo della frazione di tempo (Time Slice):
    • I fotogrammi al secondo (FPS) predefiniti sono impostati a 30, quindi viene calcolata una durata del lotto di circa 33ms.
  2. Controllo shouldYield():
    • Prima di elaborare ciascun elemento, la funzione controlla quanto tempo è trascorso dall'ultimo yield.
    • Se supera la soglia (ad es. circa 33ms, o 500ms se il documento è nascosto), cede nuovamente il controllo al browser.
  3. Meccanismi di Yielding:
    • Pagina nascosta: utilizza setTimeout(resolve, 1) — il tempo minimo per consentire ad altri task di inserirsi.
    • Pagina visibile: utilizza una combinazione di requestAnimationFrame e un breve timeout. Se il metodo sperimentale scheduler.yield() è disponibile, chiama anche quello.

Dividendo il ciclo in lotti, il browser ha lo spazio di manovra necessario per renderizzare la pagina, rispondere agli input dell'utente ed eseguire altri script, evitando così il temuto problema della "pagina che non risponde".

Perché ne avete bisogno #

Prossimi passi #

Ringraziamenti #

Un ringraziamento speciale a Rick Viscomi per aver scritto l'articolo su PerfPlanet che mi ha spinto a realizzare questo strumento. Suddividere i task di grandi dimensioni in blocchi più piccoli è diventata una strategia prestazionale chiave, e yieldy-for-loop mira a renderne ancora più semplice l'adozione.

Conclusione #

I cicli lunghi non devono per forza tradursi in interfacce utente bloccate. Cedendo periodicamente il controllo al browser, potete mantenere un'esperienza fluida per i vostri utenti. yieldy-for-loop si occupa della parte difficile con pochissimo codice, lasciandovi liberi di concentrarvi su ciò che sapete fare meglio: creare fantastiche applicazioni web.

Se avete domande, contattatemi o aprite una segnalazione su GitHub. Ora non vi resta che provarlo e mantenere i vostri cicli fluidi.