将对象传递给Web工作者

我想通过postMessage函数传递一个对象给一个web worker。
这个对象是一个正方形,有几个function可以在canvas上绘制自己,还有其他一些东西。 networking工作者mus返回这个对象的数组。
问题是,当我用这个对象调用postMessage函数时,我得到一个这样的错误:

Uncaught Error: DATA_CLONE_ERR: DOM Exception 25 

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

有没有人有类似的问题? 你知道一些workarround这个?
提前致谢。

有几个原因可能会导致您提到的错误, 原因在这里列出 。

将对象发送给Web工作人员时,如果对象是可序列化的对象,则该对象将被序列化,然后在Web Worker中反序列化。

这意味着你发送给web worker的对象的方法不是可以传递给web worker的东西(导致你遇到的错误),你需要为对象提供必要的方法/函数在networking工作者的环境中,确保它们不是传递给networking工作者的对象的一部分。

正如您怀疑带有function的对象不能被张贴。 recursion引用的对象也是如此,但最近在某些浏览器中已经发生了变化。 您可以在脚本的开头执行testing,以确定哪些函数用于发送/接收数据,而不必担心为每个post进行手动和昂贵的冗余序列化。

我遇到了同样的问题,通过将几乎所有的代码移动到worker中,并在主线程中保留一个渲染器(包装2d上下文渲染器)来解决这个问题。 在工作人员中,我将用于canvas的不同绘制调用序列化为(types)数组中的数字。 这个数组然后被发布到主线程。

所以,例如,当我想绘制一个图像,我调用我的工人的渲染器实例上的drawImage()方法。 该调用被翻译成类似[13,1,50,40]东西,这对应于绘制方法enum,图像唯一id和它的xy坐标。 多个调用被缓冲并放入同一个数组中。 在更新循环结束时,数组被发布到主线程。 接收主渲染器实例分析数组并执行适当的绘制调用。

对象和web工作者的真正问题在于对象的方法。 一个对象不应该只有属性的方法。

例如:

 var myClass = function(){ this.a = 5; this.myMethod = function(){} } var notParseableObject = new myClass(); var myClass2 = function(){ this.a = 5; } var parseableObject = new myClass2(); 

第一个不会工作(与提及的错误消息)与postMessage和第二个将工作。

我最近在使用networking工作者时遇到了同样的问题。 我传给我的工人的任何东西都保留了所有的属性,但神秘地失去了所有的方法。

您必须在Web Worker脚本本身中定义方法。 一个解决方法是importScripts的类定义,并手动设置__proto__属性的任何东西你收到。 在我的情况下,我想传递一个grid.js定义的grid对象( grid.js ,我在2048年工作),并做了这样的事情:

 importScripts('grid.js') onMessage = function(e) { e.data.grid.__proto__ = Grid.prototype; ... } 

看看vkThread插件

http://www.eslinstructor.net/vkthread/

它可以将函数传递给工作者,包括带有上下文的函数(对象的方法)。 它也可以传递函数的依赖关系,匿名函数和lambdaexpression式。

–Vadim

将数据传递给Web Worker时,将使用结构化克隆algorithm创build数据的副本 。 它在HTML5中有规定(见§2.9:安全传递结构化数据 )。

MDN 概述了支持的types 。 由于函数不被支持,试图克隆包含函数的对象将会抛出一个DATA_CLONE_ERRexception。

如果你有一个function的对象怎么办?

  • 如果function不相关,请尝试创build一个仅包含要传输的数据的新对象。 只要你只使用支持的types,发送应该工作。 使用JSON.stringifyJSON.parse也可以用作解决方法,因为stringify忽略了函数。

  • 如果function是相关的,那么没有便携的方法。 有尝试使用toStringeval的组合(例如,由jsonfs库使用),但是这在所有情况下都不起作用。 例如,如果你的函数是本地代码,它将会中断。 closures也是有问题的。