将对象传递给Web worker

dgi*_*ian 52 javascript web-worker

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

Uncaught Error: DATA_CLONE_ERR: DOM Exception 25
Run Code Online (Sandbox Code Playgroud)

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

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

eri*_*old 51

您提到的错误可能会被抛出的原因有几个,原因列在这里.

将对象发送给Web worker时,对象将被序列化,如果对象是可序列化对象,则稍后在Web worker中反序列化.

这意味着您发送给Web worker的对象的方法不能传递给Web worker(导致您遇到的错误),并且您需要为对象提供必要的方法/函数在Web工作者的环境中,并确保它们不是传递给Web worker的对象的一部分.

  • -1.您可以将对象发送给Webworkers.什么浏览器不是JSON-(反)序列化,而是[结构化克隆](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/The_structured_clone_algorithm). (33认同)
  • 一些(大多数)浏览器自动JSON.parse/JSON.stringify您尝试传递给Web工作者/从Web工作者传递的对象,但他们并非都这样做,因此您应该假设他们都没有这样做. (7认同)
  • @Bergi - 纠正可能采用的结构化克隆算法,但结构化克隆算法不能复制错误和函数对象; 尝试这样做会抛出DATA_CLONE_ERR异常.这直接涉及OP问题,并解释了有问题的错误. (5认同)
  • 它发送对象(对象,数组)但不起作用时有效 (2认同)

ben*_*ich 13

因为您怀疑具有功能的对象无法发布.具有递归引用的对象也是如此,但最近在某些浏览器中已经发生了变化.您可以在脚本开头执行测试,以确定用于发送/接收数据的功能,而不是冒着为每个帖子进行手动和昂贵的冗余序列化的风险.

我遇到了同样的问题并通过将几乎所有代码移动到worker中并且只在主线程中保留渲染器(包装2d上下文渲染器)来解决它.在worker中,我将用于画布的不同绘制调用序列化为(类型)数组中的数字.然后将此数组发布到主线程.

因此,例如,当我想绘制图像时,我drawImage()在worker中的worker worker渲染器实例上调用该方法.该调用被转换为类似于[13,1,50,40]绘制方法枚举,图像唯一ID及其xy坐标的内容.多个调用被缓冲并放在同一个数组中.在更新循环结束时,数组将发布到主线程.接收主渲染器实例解析数组并执行适当的绘制调用.


xua*_*nji 8

我最近在使用Web worker时遇到了同样的问题.我传给工人的任何东西都保留了它的所有属性,但神秘地丢失了它的所有方法.

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

importScripts('grid.js')

onMessage = function(e) {
  e.data.grid.__proto__ = Grid.prototype;
  ...
}
Run Code Online (Sandbox Code Playgroud)

  • 不要手动设置 __proto__ ! (3认同)

Phi*_*ßen 8

当您将数据传递给 Web Worker 时,会使用结构化克隆算法制作数据副本。它在 HTML5 中指定(参见第 2.9 节:结构化数据的安全传递)。

MDN 有支持类型概述。由于不支持函数,因此尝试克隆包含函数的对象将引发DATA_CLONE_ERR异常。

如果你有一个带有函数的对象怎么办?

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

  • 如果功能相关,则没有可移植的方式。有尝试使用的组合toStringeval(例如,用于由jsonfs库),但这并不适用于所有情况。例如,如果您的函数是本机代码,它就会中断。闭包也是有问题的。


Jos*_*abo 5

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

例如:

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


var myClass2 = function(){
    this.a = 5;
}
var parseableObject = new myClass2();
Run Code Online (Sandbox Code Playgroud)

第一个不会与postMessage一起工作(带有提到的错误消息),第二个将工作。