将对象传递给Web worker

时间:2011-10-09 14:51:47

标签: javascript web-worker

我正在尝试通过postMessage函数将对象传递给Web worker 这个对象是一个正方形,有一些功能可以在画布上绘制自己和其他一些东西。 Web worker必须返回此对象的数组 问题是当我用这个对象调用postMessage函数时,我得到一个错误:

Uncaught Error: DATA_CLONE_ERR: DOM Exception 25

我得到的就是将对象发送给工人,反之亦然 我认为错误是因为javascript必须序列化对象,但不能这样做,因为该对象具有内置函数。

有没有人遇到过类似的问题?你知道这方面的一些工作吗?
提前谢谢。

8 个答案:

答案 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.stringifyJSON.parse也可以用作解决方法,因为stringify会忽略函数。

  • 如果功能相关,则没有便携方式。尝试使用toStringeval的组合(例如,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);   
});