OffscreenCanvas – Canvas-Vorgänge mit einem Web Worker beschleunigen

Tim Dresser

Canvas ist eine beliebte Möglichkeit, das Zeichnen verschiedenster Grafiken auf dem Bildschirm und der Einstiegspunkt in die Welt von WebGL. Damit lassen sich Formen und Bilder zeichnen, Animationen ausführen und sogar Videoinhalte darstellen und verarbeiten. Es wird oft verwendet, um ansprechende Nutzererfahrungen in medienintensiven Webanwendungen und Online-Spiele.

Es ist skriptfähig, d. h., die auf dem Canvas gezeichneten Inhalte können programmatisch erstellt werden. zum Beispiel in JavaScript. Dadurch ist Canvas sehr flexibel.

Gleichzeitig ist bei modernen Websites die Skriptausführung eine der häufigsten Quellen von Problemen mit der Reaktionsfähigkeit von Nutzern. Da die Canvas-Logik und das Rendering im selben Thread wie die Nutzerinteraktion Die (manchmal aufwendigen) Berechnungen für Animationen können dem eigentlichen und wahrgenommene Leistung.

Zum Glück lässt sich OffscreenCanvas eine Reaktion auf diese Bedrohung ist.

Unterstützte Browser

  • 69
  • 79
  • 105
  • 16.4

Quelle

Bisher waren die Canvas-Zeichenfunktionen an das <canvas>-Element gebunden. Das bedeutete, dass dies direkt vom DOM abhängig war. OffscreenCanvas, wie der Name schon sagt, entkoppelt das DOM und die Canvas API, indem es aus dem Bildschirm verschoben wird.

Durch diese Entkopplung wird das Rendering von OffscreenCanvas vollständig vom DOM und der bietet im Vergleich zum regulären Canvas einige Geschwindigkeitsverbesserungen, da keine Synchronisierung erfolgt. zwischen den beiden.

Was jedoch noch wichtiger ist, ist, dass es in einem Web Worker verwendet werden kann, obwohl es keine DOM verfügbar. Dies ermöglicht viele interessante Anwendungsfälle.

OffscreenCanvas in einem Worker verwenden

Mitarbeiter sind die Web-Version von Threads. Mit ihnen können Aufgaben im Hintergrund ausgeführt werden.

Wenn Sie einige Ihrer Scripts auf einen Worker verlagern, haben Sie mehr Spielraum für nutzerkritische Aufgaben in Ihrer App. Aufgaben im Hauptthread. Ohne OffscreenCanvas konnte die Canvas API nicht in einem Worker verwendet werden, war kein DOM verfügbar.

OffscreenCanvas ist nicht vom DOM abhängig und kann daher verwendet werden. Im folgenden Beispiel wird OffscreenCanvas verwendet So berechnen Sie in einem Worker die Farbe eines Farbverlaufs:

// 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 )

Blockierung des Hauptthreads aufheben

Wenn Sie schwere Berechnungen zu einem Mitarbeiter verlagern, auf wichtige Ressourcen im Hauptthread. Verwenden Sie die Funktion transferControlToOffscreen. zum Spiegeln des regulären Canvas-Elements in eine OffscreenCanvas-Instanz. Vorgänge angewendet auf OffscreenCanvas wird automatisch auf dem Quell-Canvas gerendert.

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

Im folgenden Beispiel erfolgt die intensive Berechnung, wenn sich das Farbschema ändert. selbst auf einem schnellen Desktop-Computer noch einige Millisekunden in Anspruch nehmen. Sie können Animationen im Hauptthread ausführen. oder im Worker befinden. Im Hauptthread können Sie nicht mit der Schaltfläche interagieren, während der schwere Task wird ausgeführt – der Thread ist blockiert. Für den Worker gibt es keine Auswirkungen auf Reaktionsfähigkeit der Benutzeroberfläche

<ph type="x-smartling-placeholder">
</ph>
Demo

Andersherum funktioniert es auch: Der beschäftigte Hauptthread hat keinen Einfluss auf die Animation, die auf Arbeitskräfte. Sie können diese Funktion verwenden, um visuelle Verzögerungen zu vermeiden und eine flüssige Animation zu gewährleisten. trotz Hauptthread-Traffic, wie in der folgenden Demo gezeigt.

<ph type="x-smartling-placeholder">
</ph>
Demo

Bei einem normalen Canvas wird die Animation gestoppt, wenn der Hauptthread künstlich überarbeitet wird. während die Arbeit im OffscreenCanvas flüssig läuft.

Da die OffscreenCanvas API im Allgemeinen mit dem regulären Canvas-Element kompatibel ist, können Sie und auch mit einigen der führenden Grafikbibliotheken auf dem Markt nutzen.

Sie können beispielsweise eine Feature-Erkennung durchführen und, falls verfügbar, mit Three.js verwenden, indem Sie Folgendes angeben: der Canvas-Option im Renderer-Konstruktor:

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});

Eine Sache ist, dass Three.js erwartet, dass Canvas die Eigenschaften style.width und style.height hat. Da OffscreenCanvas nicht vom DOM getrennt ist, müssen Sie es selbst bereitstellen. entweder durch Stubbieren oder durch Bereitstellen einer Logik, die diese Werte mit dem Original Canvas-Abmessungen.

Im Folgenden wird gezeigt, wie eine einfache Three.js-Animation in einem Worker ausgeführt wird:

<ph type="x-smartling-placeholder">
</ph>
Demo

Bedenken Sie, dass einige der DOM-bezogenen APIs nicht ohne Weiteres in einem Worker verfügbar sind. Wenn Sie also Wenn Sie erweiterte Three.js-Funktionen wie Texturen verwenden möchten, benötigen Sie möglicherweise weitere Behelfslösungen. Einige Anregungen für erste Experimente finden Sie in der Video von der Google I/O 2017

Wenn Sie die grafischen Möglichkeiten von Canvas intensiv nutzen, kann die Nutzung von OffscreenCanvas die Leistung Ihrer App beeinflussen. Die Bereitstellung von Canvas-Renderingkontexten für Worker erhöht sich Parallelität in Webanwendungen und macht die Nutzung von Mehrkernsystemen besser.

Zusätzliche Ressourcen