我正在尝试通过postMessage函数将对象传递给Web worker 这个对象是一个正方形,有一些功能可以在画布上绘制自己和其他一些东西。 Web worker必须返回此对象的数组 问题是当我用这个对象调用postMessage函数时,我得到一个错误:
Uncaught Error: DATA_CLONE_ERR: DOM Exception 25
我得到的就是将对象发送给工人,反之亦然 我认为错误是因为javascript必须序列化对象,但不能这样做,因为该对象具有内置函数。
有没有人遇到过类似的问题?你知道这方面的一些工作吗?
提前谢谢。
答案 0 :(得分:49)
有几个原因可以解释您提到的错误,the reasons are listed here。
将对象发送给Web worker时,对象将被序列化,如果对象是可序列化对象,则稍后在Web worker中反序列化。
这意味着您发送给Web worker的对象的方法不能传递给Web worker(导致您遇到的错误),并且您需要提供必要的方法/函数到Web工作者环境中的对象,并确保它们不是传递给Web worker的对象的一部分。
答案 1 :(得分:12)
因为您怀疑具有功能的对象无法发布。具有递归引用的对象也是如此,但最近在某些浏览器中已经发生了变化。您可以在脚本开头执行测试,以确定用于发送/接收数据的函数,而不是冒着为每个帖子进行手动和昂贵的冗余序列化的风险。
我遇到了同样的问题并通过将几乎所有代码移动到worker中并且仅在主线程中保留渲染器(包装2d上下文渲染器)来解决它。在工作者中,我将用于画布的不同绘制调用序列化为(类型)数组中的数字。然后将此数组发布到主线程。
因此,例如,当我想绘制图像时,我在worker中的worker renderer实例上调用drawImage()
方法。该调用被转换为类似[13,1,50,40]
的内容,其对应于绘制方法枚举,图像唯一ID及其xy坐标。多个调用被缓冲并放在同一个数组中。在更新循环结束时,数组将发布到主线程。接收主渲染器实例解析数组并执行适当的绘制调用。
答案 2 :(得分:6)
我最近在使用网络工作时遇到了同样的问题。我传给工人的任何东西都保留了它的所有属性,但神秘地丢失了它的所有方法。
您必须在Web worker脚本本身中定义方法。一种解决方法是importScripts
类定义并手动设置您收到的任何内容的__proto__
属性。在我的情况下,我想传递一个grid
对象,在grid.js
中定义(是的,我在2048年工作),并且这样做:
importScripts('grid.js')
onMessage = function(e) {
e.data.grid.__proto__ = Grid.prototype;
...
}
答案 3 :(得分:4)
对象和webworkers的真正问题在于该对象的方法。一个对象不应该只有属性方法。
例如:
var myClass = function(){
this.a = 5;
this.myMethod = function(){}
}
var notParseableObject = new myClass();
var myClass2 = function(){
this.a = 5;
}
var parseableObject = new myClass2();
第一个不会用postMessage工作(带有提到的错误信息),第二个工作。
答案 4 :(得分:3)
将数据传递给Web worker时,会使用structured clone algorithm创建数据副本。它在HTML5中指定(请参阅§ 2.9: Safe passing of structured data)。
MDN有overview of supported types。由于不支持函数,因此尝试克隆包含函数的对象将抛出DATA_CLONE_ERR
异常。
如果您有一个具有功能的对象该怎么办?
如果函数不相关,请尝试创建仅包含要传输的数据的新对象。只要您只使用支持的类型,send就可以了。使用JSON.stringify
和JSON.parse
也可以用作解决方法,因为stringify
会忽略函数。
如果功能相关,则没有便携方式。尝试使用toString
和eval
的组合(例如,jsonfs库使用),但这并不适用于所有情况。例如,如果您的函数是本机代码,它将会中断。封闭也是有问题的。
答案 5 :(得分:1)
查看 vkThread 插件
http://www.eslinstructor.net/vkthread/
它可以将函数传递给worker,包括带上下文的函数(object的方法)。它还可以传递具有依赖项,匿名函数和lambda的函数。
- 瓦迪姆
答案 6 :(得分:0)
某些类型的对象,例如ArrayBuffer和ImageBitmap,具有Transferable接口实现,可以在不复制Object的情况下进行传输。
这在Canvas + Web worker的上下文中非常有用,因为您可以节省在线程之间复制数据的时间。
答案 7 :(得分:-1)
如果要使用方法传递对象,可以对其进行字符串化并在接收端进行解析。
postMessage(JSON.stringify(yourObject)
在侦听器中
this.worker.addEventListener('message', (event) => {
const currentChunk = JSON.parse(event.data);
});