61

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

Uncaught Error: DATA_CLONE_ERR: DOM Exception 25

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

有没有人遇到过类似的问题?你知道一些解决方法吗?
提前致谢。

4

8 回答 8

54

您提到的错误可能被抛出有几个原因,原因在此处列出

当向 web worker 发送对象时,对象会被序列化,如果对象是可序列化的对象,则稍后会在 web worker 中反序列化。

这意味着您发送给 Web Worker 的对象的方法不是可以传递给 Web Worker 的东西(导致您遇到的错误),您需要为对象提供必要的方法/功能在环境的网络工作者一侧,并确保它们不是传递给网络工作者的对象的一部分。

于 2011-10-09T19:03:47.770 回答
13

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

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

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

于 2012-01-18T23:58:24.997 回答
9

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

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

importScripts('grid.js')

onMessage = function(e) {
  e.data.grid.__proto__ = Grid.prototype;
  ...
}
于 2014-04-20T10:27:19.777 回答
8

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

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

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

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

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

于 2017-07-09T22:04:59.157 回答
5

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

前任:

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


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

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

于 2012-09-04T13:34:08.127 回答
2

看看vkThread插件

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

它可以将函数传递给工作人员,包括带有上下文的函数(对象的方法)。它还可以传递具有依赖关系的函数、匿名函数和 lambda。

——瓦迪姆

于 2013-07-30T15:06:59.180 回答
1

某些类型的对象,如 ArrayBuffer 和 ImageBitmap,它们具有Transferable接口实现,可以在不复制 Object 的情况下进行传输。

这在 Canvas + Web worker 的上下文中非常有用,因为您可以节省在线程之间复制数据的时间。

于 2018-07-10T13:48:56.900 回答
-1

如果您想使用方法传递对象,您可以对其进行字符串化并在接收端对其进行解析。

postMessage(JSON.stringify(yourObject)

在听者中

this.worker.addEventListener('message', (event) => {
   const currentChunk = JSON.parse(event.data);   
});
于 2020-01-30T17:48:57.450 回答