可以将CanvasPixelArray
获取的via 发送getImageData
到worker脚本,让worker脚本操纵其后台线程中的像素,最后将操作的像素阵列发回.
但是,我使用的是原生画布绘图功能drawImage
.这些drawImage
调用当前正在阻止UI线程.这会导致按钮重绘速度慢,单击按钮时会出现明显的延迟,这只是为了说明一些缺点.(编辑:现在可以使用ctx.imageSmoothingEnabled = false
至少在带有webkit
前缀的WebKit上完成一项小改进.)
我想使用Web Workers将绘图从主线程移动到后台线程中.但是,我似乎无法向工作人员发送画布和上下文.
我确实在MDN上发现了这个通知:
注意:像往常一样,后台线程(包括worker)无法操纵DOM.如果后台线程采取的操作需要导致对DOM的更改,则应将消息发送回其创建者以执行该工作.
但是我想按原样离开DOM; 我只是想在canvas元素上绘制东西.这是可能的,还是Web Workers真的只允许计算而不是绘制?
(或者也许可以使用类似drawImage
操作CanvasPixelArray
而不是在画布上绘制的函数?)
[编辑〜5年后:其中一些已经开始改变,并且有新的Web平台功能实际上允许从工作者渲染到画布!有关详细信息,请参阅此博客:https://hacks.mozilla.org/2016/01/webgl-off-the-main-thread/ - 其余答案均提供2011年时代信息;)]
Web工作者只能计算,而不能修改DOM或进行任何调用以绘制到画布.但是就像你说的那样,你可以向网络工作者发布一个像素数组,以便在那里进行处理并将其发回.由于这是异步的,我不明白为什么会导致UI线程的任何减速,除非你故意阻止,直到web worker响应(你不应该).
所以你的drawImage
电话花了这么长时间才会影响用户界面似乎很奇怪.这些天大多数画布都是硬件加速的,所以它们应该很好地跳过.我的猜测是你每帧通过一个web worker绘制一个画布像素数组,这实际上意味着你是用javascript渲染画布的软件.Javascript仍然太慢了 - 即使C++软件渲染器也很慢,这就是硬件加速很重要的原因.所以,你可以在渲染网络工作者的东西在画布像素阵列一次,然后当你得到你的结果它缓存在一个Image
曾经,然后绘制Image
到画布上,就像你喜欢.那应该还是非常快.
编辑:你可能想要查看WebGL,在那里你可以编写片段着色器,它实际上是处理像素效果的小程序.它们完全在显卡上运行,所以它们的速度非常愚蠢.
[社区编辑:这个答案是在2011年编写并被接受的.其他技术已经出现(或正在出现),可以让Web Workers和Canvas更好地共存; 除了这个答案,读者应该知道本页面上的所有答案.]
您无法将画布对象或画布上下文传递给工作线程,因为画布是DOM的一部分.
您可以将其发布ImageData
到Web Worker,后者将操纵的内容发送ImageData
回调用者(主UI)线程.
例如:
创建Web Worker:
this.renderer = new Worker("renderer.js");
ImageData
将从画布创建的内容发布到Web Worker:
var ctx = this.canvas.getContext('2d'); var imageData = ctx.createImageData(width, height); this.renderer.postMessage({ image: imageData });
做ImageData
操纵Web工作,并张贴回主线程:
onmessage = function(e) { var processedImage = self.doImageProcessing(e.data.image); postMessage({ image: processedImage }); };
将操纵设置ImageData
为主线程中的画布:
this.renderer.onmessage = function (e) { var ctx = this.canvas.getContext('2d'); ctx.putImageData(e.data.image, 0, 0); }
有一个新的API可以执行此操作(当前,只有启用了pref才受Firefox支持)。
请参阅https://developer.mozilla.org/zh-CN/docs/Web/API/OffscreenCanvas和 https://hacks.mozilla.org/2016/01/webgl-off-the-main-thread/。