使用Web Workers使用本地画布函数进行绘图

Using Web Workers for drawing using native canvas functions

本文关键字:函数 绘图 布函数 Workers Web 使用      更新时间:2023-09-26

可以将通过getImageData获得的CanvasPixelArray发送给worker脚本,并让worker脚本在其后台线程中操作像素,并最终将操作后的像素数组返回。

然而,我使用本地画布绘制功能,如drawImagedrawImage调用当前阻塞UI线程。这将导致按钮重绘缓慢,并且在单击按钮时出现明显的延迟,仅举几个缺点。(编辑:一个小的改进现在可以完成与ctx.imageSmoothingEnabled = false,至少在WebKit与webkit前缀。)

我想将绘图从主线程移动到使用Web Workers的后台线程。但是,我似乎无法将画布或上下文发送给worker。

我确实在MDN上发现了这个通知:

注意:像往常一样,后台线程——包括工作线程——不能操作DOM。如果后台线程所采取的操作需要导致DOM的更改,它们应该向其创建者发送消息以完成该工作。

但是我想让DOM保持原样;我只是想在画布元素上画东西。这是可能的吗?或者Web worker真的只允许计算而不允许绘制吗?

(或者也许可以使用像drawImage这样的函数来操纵CanvasPixelArray而不是在画布上绘图?)

[编辑~5年后:其中一些开始改变,并且有新的web平台功能实际上允许从Worker渲染到画布!有关更多信息,请参阅此博客:https://hacks.mozilla.org/2016/01/webgl-off-the-main-thread/-答案的其余部分提供了2011年的信息;)]

Web工作者只能计算,不能修改DOM,也不能调用绘制画布。然而,就像你说的,你可以发布一个像素数组到一个网络工作者处理它,并发布回来。因为这是异步的,我不明白为什么这会导致UI线程的任何减速,除非你故意阻塞直到web worker响应(这是你不应该的)。

所以看起来很奇怪,你的drawImage调用花了这么长时间,它影响了UI。现在大多数画布都是硬件加速的,所以它们应该很好地跳过。我的猜测是,你是通过一个web工作者绘制画布像素数组每帧,这实际上意味着你是软件渲染画布在javascript。Javascript仍然太慢,无法做到这一点——甚至c++软件渲染器也有点慢,这就是为什么硬件加速很重要。所以你可以渲染一些东西到画布像素数组在一个web工作者一次,然后当你得到你的结果缓存到一个Image 一次,然后画的Image到画布,你喜欢多少。那应该还是很快的。

编辑:你可能想看看WebGL,在那里你可以写片段着色器,这是有效的小程序来处理像素效果。它们完全在显卡上运行,所以速度非常快。

你可以将ImageData发送给Web Worker,它将被操纵的ImageData发送回调用者(主UI)线程。

例如:

  1. 创建Web Worker:

    <>之前。
  2. 将从画布创建的ImageData发布到Web Worker:

    var ctx = this.canvas.getContext('2d');var imageData = ctx。createImageData(宽度、高度);this.renderer。postMessage({image: imageData});
  3. 在Web Worker中执行ImageData操作并将其发送回主线程:

    onmessage = function(e) {var proces沉淀物= self.doImageProcessing(.data.image);postMessage({image: processediment});}; 
  4. 在主线程中设置被操纵的ImageData到画布:

    this.renderer。Onmessage = function (e) {var ctx = this.canvas.getContext('2d');ctx.putImageData (e.data。Image, 0,0);} 

有一个新的API可以做到这一点(目前只有在Firefox中启用pref时才支持)。

参见https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas和https://hacks.mozilla.org/2016/01/webgl-off-the-main-thread/。

[社区编辑:这个答案是在2011年编写并接受的。其他技术已经出现(或正在出现),它们可能会让Web Workers和Canvas更好地共存;

读者应该知道本页除了这个答案之外的所有答案。

你不能将画布对象或画布上下文传递给工作线程,因为画布是DOM的一部分。