将对象传递给网络工作者

IT技术 javascript web-worker
2021-02-22 14:00:24

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

Uncaught Error: DATA_CLONE_ERR: DOM Exception 25

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

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

6个回答

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

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

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

当您发送对象(对象,数组)时它有效,但不起作用
2021-04-23 14:00:24
@Bergi - 纠正可能采用结构化克隆算法,但结构化克隆算法不能复制 Error 和 Function 对象;尝试这样做将引发 DATA_CLONE_ERR 异常。这直接与 OP 问题相关,并解释了有问题的错误。
2021-04-24 14:00:24
我尝试过发送数组,并且奏效了。我会尝试发送一些没有成员函数的对象,看看会发生什么。非常感谢你的帮助。
2021-04-30 14:00:24

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

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

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

我正在传递带有函数的对象。它们的功能不会被复制,但对象发布得很好。
2021-05-02 14:00:24
优秀。通过可传输对象实现的远程调用是非常干净和高效的解决方案。
2021-05-16 14:00:24

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

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

importScripts('grid.js')

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

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

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

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

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

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

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

前任:

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


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

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

@DavidThielen,我现在还没有尝试过,但在提出问题时这是正确的行为描述。也许这种行为是一个错误,现在浏览器只是用一个函数作为值来“过滤”这个属性(在我看来这是理想的行为)。但是在任何情况下都不可能向网络工作者传递一个函数指针。无论如何,正如我所说,我无法确认,因为我现在还没有尝试过;)
2021-04-27 14:00:24