OffscreenCanvas: velocizza le operazioni del canvas con un worker web

Tim Dresser

Canvas è un modo diffuso di disegnare tutti i tipi di grafica sullo schermo e un punto di accesso al mondo di WebGL. Può essere utilizzato per disegnare forme, immagini, eseguire animazioni o anche per visualizzare ed elaborare contenuti video. Viene spesso utilizzato per creare esperienze utente stupende in applicazioni web ricche di contenuti multimediali e giochi online.

Possono essere creati tramite script, il che significa che i contenuti disegnati su canvas possono essere creati in modo programmatico, ad esempio in JavaScript. Ciò garantisce alla tela una grande flessibilità.

Allo stesso tempo, nei siti web moderni, l'esecuzione di script è una delle fonti di problemi di reattività degli utenti. Poiché la logica e il rendering del canvas avvengono sullo stesso thread dell'interazione dell'utente, i calcoli (a volte complessi) coinvolti nelle animazioni possono danneggiare il e prestazioni percepite.

Fortunatamente, OffscreenCanvas è una risposta a quella minaccia.

Supporto dei browser

  • 69
  • 79
  • 105
  • 16.4

Origine

In precedenza, le funzionalità di disegno del canvas erano associate all'elemento <canvas>, il che significava che dipendeva direttamente dal DOM. OffscreenCanvas, come suggerisce il nome, disaccoppia il DOM e l'API Canvas spostandolo fuori dallo schermo.

Grazie a questo disaccoppiamento, il rendering di OffscreenCanvas viene scollegato completamente dal DOM offre quindi alcuni miglioramenti della velocità rispetto al canvas normale, in quanto non è disponibile tra i due.

Ma soprattutto è che può essere utilizzato in un web worker, anche se non c'è DOM disponibile. Ciò consente tutti i tipi di casi d'uso interessanti.

Usa OffscreenCanvas in un worker

Lavoratori sono la versione dei thread web: ti consentono di eseguire attività in background.

Spostare parte degli script a un worker offre alla tua app più spazio per eseguire operazioni critiche per l'utente più attività sul thread principale. Senza OffscreenCanvas, non era possibile utilizzare l'API Canvas in un worker, non era disponibile alcun DOM.

OffscreenCanvas non dipende dal DOM, quindi può essere utilizzato. L'esempio seguente utilizza OffscreenCanvas per calcolare un colore sfumato in un worker:

// file: worker.js
function getGradientColor(percent) {
  const canvas = new OffscreenCanvas(100, 1);
  const ctx = canvas.getContext('2d');
  const gradient = ctx.createLinearGradient(0, 0, canvas.width, 0);
  gradient.addColorStop(0, 'red');
  gradient.addColorStop(1, 'blue');
  ctx.fillStyle = gradient;
  ctx.fillRect(0, 0, ctx.canvas.width, 1);
  const imgd = ctx.getImageData(0, 0, ctx.canvas.width, 1);
  const colors = imgd.data.slice(percent * 4, percent * 4 + 4);
  return `rgba(${colors[0]}, ${colors[1]}, ${colors[2]}, ${colors[3]})`;
}

getGradientColor(40);  // rgba(152, 0, 104, 255 )

Sblocca thread principale

Spostare un calcolo pesante su un worker consente di liberare più risorse significative sul thread principale. Usa transferControlToOffscreen per eseguire il mirroring del canvas normale a un'istanza OffscreenCanvas. Operazioni applicate a OffscreenCanvas verrà visualizzato automaticamente nel canvas di origine.

const offscreen = document.querySelector('canvas').transferControlToOffscreen();
const worker = new Worker('myworkerurl.js');
worker.postMessage({canvas: offscreen}, [offscreen]);

Nell'esempio seguente, il calcolo pesante si verifica quando il tema a colori cambia: impiegano alcuni millisecondi anche su un desktop veloce. Puoi scegliere di eseguire animazioni sul thread principale o nel worker. Nel caso del thread principale, non puoi interagire con il pulsante dell'attività è in esecuzione: il thread è bloccato. Nel caso del lavoratore, non c'è alcun impatto sul Reattività della UI.

Demo

Funziona anche nell'altro modo: il thread principale occupato non influisce sull'animazione in esecuzione. un worker. Puoi usare questa funzionalità per evitare i blocchi visivi e garantire un'animazione fluida. nonostante il traffico del thread principale, come mostrato nella demo seguente.

Demo

Nel caso di un canvas normale, l'animazione si interrompe quando il thread principale viene sovraccaricato in modo artificiale. mentre OffscreenCanvas basato su worker esegue senza problemi.

Poiché l'API OffscreenCanvas è generalmente compatibile con il normale elemento Canvas, puoi da usare come miglioramento progressivo, anche con alcune delle principali librerie grafiche sul mercato.

Ad esempio, puoi rilevarla in base alle caratteristiche e, se disponibile, utilizzarla con Three.js specificando l'opzione canvas nel costruttore del renderer:

const canvasEl = document.querySelector('canvas');
const canvas =
  'OffscreenCanvas' in window
    ? canvasEl.transferControlToOffscreen()
    : canvasEl;
canvas.style = {width: 0, height: 0};
const renderer = new THREE.WebGLRenderer({canvas: canvas});

Il fatto è che Three.js si aspetta che il canvas abbia una proprietà style.width e style.height. OffscreenCanvas, in quanto completamente scollegato dal DOM, non dispone di tale funzionalità, quindi devi fornirlo personalmente, tramite una ricostruzione o fornendo una logica che leghi questi valori all'originale dimensioni del canvas.

Di seguito viene illustrato come eseguire un'animazione Three.js di base in un worker:

Demo

Ricorda che alcune API correlate a DOM non sono immediatamente disponibili in un worker, quindi se Se vuoi usare funzionalità di Three.js più avanzate come le texture, potresti aver bisogno di altre soluzioni. Per farti un'idea su come iniziare a sperimentare con questi strumenti, dai un'occhiata alle di Google I/O 2017.

Se stai facendo un uso intensivo delle funzionalità grafiche della tela, OffscreenCanvas può influenzare le prestazioni della tua app. Rendere disponibili ai worker i contesti di rendering del canvas aumenta il parallelismo nelle applicazioni web e sfrutta meglio i sistemi multi-core.

Risorse aggiuntive