javascript - Usar Web Workers para dibujar usando funciones canvas nativas
html5-canvas web-worker (4)
Hay una nueva API para hacer esto (actualmente solo es compatible con Firefox si habilitas un pref).
Consulte https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas y https://hacks.mozilla.org/2016/01/webgl-off-the-main-thread/ .
Es posible enviar un CanvasPixelArray
obtenido a través de getImageData
a un script de trabajador, y dejar que el script de trabajador manipule los píxeles en su hilo de fondo, y eventualmente vuelva a publicar el conjunto de píxeles manipulados.
Sin embargo, estoy usando funciones nativas de dibujo de lienzo, como drawImage
. Las llamadas a drawImage
actualmente están bloqueando el hilo de UI. Esto ocasiona que los botones se vuelvan a dibujar lentamente y un retraso notable al hacer clic en un botón, solo por nombrar algunos inconvenientes. (Editar: ahora se puede lograr una pequeña mejora con ctx.imageSmoothingEnabled = false
, al menos en WebKit con el prefijo webkit
).
Me gustaría mover el dibujo del hilo principal a un hilo de fondo con Web Workers. Sin embargo, parece que no puedo enviar el lienzo ni el contexto al trabajador.
Encontré este aviso en MDN :
Nota: Como es habitual, los hilos de fondo, incluidos los trabajadores, no pueden manipular el DOM. Si las acciones realizadas por el hilo de fondo deben dar como resultado cambios en el DOM, deben enviar mensajes a sus creadores para que hagan ese trabajo.
Pero me gustaría dejar el DOM como está; Simplemente quiero dibujar cosas en un elemento canvas. ¿Es esto posible o solo se permite a los Trabajadores Web calcular y no dibujar?
(¿O tal vez sea posible utilizar funciones como drawImage
para manipular CanvasPixelArray
lugar de dibujar en un lienzo?)
Puede publicar ImageData
en Web Worker, que devuelve ImageData
manipulado a la ImageData
de llamadas (UI principal).
P.ej:
Crear un trabajador web:
this.renderer = new Worker("renderer.js");
Publique los
ImageData
creados desde el lienzo al Trabajador web:var ctx = this.canvas.getContext(''2d''); var imageData = ctx.createImageData(width, height); this.renderer.postMessage({ image: imageData });
Haga la manipulación de
ImageData
en Web Worker yImageData
nuevamente en Main thread:onmessage = function(e) { var processedImage = self.doImageProcessing(e.data.image); postMessage({ image: processedImage }); };
Establezca
ImageData
manipulado en el lienzo en el hilo principal:this.renderer.onmessage = function (e) { var ctx = this.canvas.getContext(''2d''); ctx.putImageData(e.data.image, 0, 0); }
[Edición ~ 5 años después: ¡algo de esto está empezando a cambiar, y hay nuevas características de plataforma web que realmente permiten renderizar un lienzo de un Trabajador! Consulte este blog para obtener más información: https://hacks.mozilla.org/2016/01/webgl-off-the-main-thread/ - el resto de la respuesta se proporciona para la información de la era 2011;)]
Los trabajadores web solo pueden calcular, no modificar el DOM o realizar llamadas para dibujar en un lienzo. Sin embargo, como dices, puedes publicar una matriz de píxeles en un trabajador web para procesarlo allí y publicarlo. Como eso es asincrónico, no veo por qué eso causaría una desaceleración en el hilo de la interfaz de usuario, a menos que bloquee deliberadamente hasta que el trabajador web responda (lo que no debería hacer).
Por lo tanto, parece extraño que las llamadas a drawImage
tomen tanto tiempo que afectan la interfaz de usuario. La mayoría de los lienzos están acelerados por hardware en estos días, por lo que deben saltarse muy bien. Supongo que está dibujando a través de un trabajador web una matriz de píxeles de lienzo en cada cuadro , lo que significa que es un software que representa el lienzo en javascript . Javascript todavía es demasiado lento para hacer esto, incluso los renderizadores de software C ++ son algo lentos, por lo que la aceleración de hardware es importante. De esta forma, puede representar algo en una matriz de píxeles de lienzo en un trabajador web una vez , y luego, cuando obtiene su resultado, lo almacena en caché en una Image
una vez y luego dibuja esa Image
en el lienzo tanto como desee. Eso debería ser realmente rápido.
Editar: es posible que desee buscar en WebGL, donde puede escribir sombreadores de fragmentos que son, de hecho, pequeños programas para procesar los efectos de píxeles. Funcionan completamente en la tarjeta gráfica, por lo que son estúpidamente rápidos.
[edición comunitaria: esta respuesta se escribió y se aceptó en 2011. Han surgido (o están surgiendo) otras tecnologías que pueden permitir que Web Workers y Canvas coexistan mejor; el lector debe conocer todas las respuestas en esta página además de esta respuesta.]
No puede pasar un objeto de lienzo o un contexto de lienzo a un hilo de trabajo porque el lienzo forma parte del DOM.