OffscreenCanvas: Acelera tus operaciones de lienzo con un trabajador web

Tim Dresser

Lienzo es una forma popular de dibujar todo tipo de gráficos en la pantalla y un punto de entrada al mundo de WebGL. Se puede usar para dibujar formas, imágenes, ejecutar animaciones o incluso mostrar y procesar contenido de video. Por lo general, se usa para crear experiencias de usuario atractivas en aplicaciones web enriquecidas con medios. juegos en línea.

Es compatible con secuencias de comandos, lo que significa que el contenido dibujado en el lienzo se puede crear de manera programática. por ejemplo, en JavaScript. Esto le da al lienzo una gran flexibilidad.

Al mismo tiempo, en los sitios web modernos, la ejecución de secuencias de comandos es una de las más frecuentes fuentes de problemas de capacidad de respuesta de los usuarios. Debido a que la lógica y la renderización del lienzo se producen en el mismo subproceso que la interacción del usuario, Los cálculos (a veces pesados) de las animaciones pueden dañar el rendimiento y el rendimiento percibido.

Por suerte, OffscreenCanvas es una respuesta a esa amenaza.

Navegadores compatibles

  • 69
  • 79
  • 105
  • 16.4

Origen

Anteriormente, las funciones de dibujo en lienzo estaban vinculadas al elemento <canvas>. lo que significaba que dependía directamente del DOM. OffscreenCanvas, como su nombre lo indica, separa el DOM y la API del lienzo moviéndolos fuera de la pantalla.

Gracias a esta separación, la renderización de OffscreenCanvas está desconectada por completo del DOM y Por lo tanto, ofrece algunas mejoras de velocidad con respecto al lienzo normal, ya que no hay sincronización. entre ambos.

Lo que es más importante, sin embargo, es que se puede usar en un Web Worker, a pesar de que no hay DOM disponible. Esto permite todo tipo de casos de uso interesantes.

Cómo usar OffscreenCanvas en un trabajador

Trabajadores son la versión web de los subprocesos, que te permiten ejecutar tareas en segundo plano.

Si transfieres algunas de tus secuencias de comandos a un trabajador, la app tendrá más margen para realizar tareas críticas tareas en el subproceso principal. Sin OffscreenCanvas, no había forma de usar la API de Canvas en un worker, ya que no había no había ningún DOM disponible.

OffscreenCanvas no depende del DOM, por lo que se puede usar. En el siguiente ejemplo, se usa OffscreenCanvas. para calcular el color del gradiente en un trabajador:

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

Desbloquear la conversación principal

Transferir un cálculo pesado a un trabajador te permite liberar recursos importantes en el subproceso principal. Usa transferControlToOffscreen para duplicar el lienzo normal en una instancia de OffscreenCanvas. Las operaciones aplicadas a OffscreenCanvas se renderizará automáticamente en el lienzo de origen.

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

En el siguiente ejemplo, el cálculo pesado ocurre cuando cambia el tema de color; debería puede tardar algunos milisegundos, incluso en un escritorio rápido. Puedes optar por ejecutar animaciones en el subproceso principal. o en el trabajador. En el caso del subproceso principal, no puedes interactuar con el botón mientras está pesado se está ejecutando la tarea, el subproceso está bloqueado. En el caso del trabajador, no hay impacto en Capacidad de respuesta de la IU

Demostración

También funciona de la otra manera: el subproceso principal ocupado no influye en la animación que se ejecuta en un trabajador. Puedes usar esta función para evitar bloqueos visuales y garantizar una animación fluida a pesar del tráfico del subproceso principal, como se muestra en la siguiente demostración.

Demostración

En el caso de un lienzo normal, la animación se detiene cuando el subproceso principal se sobrecarga artificialmente. mientras que el OffscreenCanvas basado en trabajadores se reproduce sin problemas.

Debido a que la API de OffscreenCanvas generalmente es compatible con el elemento Canvas normal, puedes lo usan como mejora progresiva, también con algunas de las bibliotecas gráficas líderes del mercado.

Por ejemplo, puedes detectarlo con atributos y, si está disponible, usarlo con Three.js especificando la opción de lienzo en el constructor del renderizador:

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

El problema aquí es que Three.js espera que el lienzo tenga una propiedad style.width y style.height. OffscreenCanvas, como está separado por completo del DOM, no lo tiene, por lo que debes proporcionarlo tú mismo. ya sea haciendo un stub o proporcionando una lógica que vincule estos valores con el original. del lienzo.

A continuación, se muestra cómo ejecutar una animación básica de Three.js en un trabajador:

Demostración

Ten en cuenta que algunas de las APIs relacionadas con el DOM no están disponibles en los trabajadores, por lo que si si quieres usar funciones más avanzadas de Three.js, como texturas, podrías necesitar más soluciones alternativas. Para obtener algunas ideas sobre cómo comenzar a experimentar con ellas, echa un vistazo a la de Google I/O 2017.

Si haces un uso intensivo de las capacidades gráficas de Canvas, OffscreenCanvas puede generar influir en el rendimiento de la app. Aumenta la disponibilidad de los contextos de renderización de lienzos para los trabajadores. paralelismo en aplicaciones web y hace un mejor uso de los sistemas de varios núcleos.

Recursos adicionales