Javascript 将对象传递给网络工作者

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7704323/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 03:15:45  来源:igfitidea点击:

Passing objects to a web worker

javascriptweb-worker

提问by dgiulian

I'm trying to pass an object to a web worker through the postMessage function.
This object is a square that has a couple of functions to draw himself on a canvas and some other things. The web worker must return an array of this objects.
The problem is that when I call the postMessage function with this object, I get an this error:

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

Uncaught Error: DATA_CLONE_ERR: DOM Exception 25

I get this both sending the object to the worker and the other way around.
I think the error is because javascript must serialize the object, but can't do it because the object has functions built-in.

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

Does anyone ever had a similar problem? Do you know some workarround to this?
Thanks in advance.

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

采纳答案by erikvold

There are a few reasons why the error that you mention could have been thrown, the reasons are listed here.

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

When sending objects to web workers, the object is serialized, and later deserialized in the web worker if the object is a serializable object.

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

This means that the methods for the objects you send to your web worker are not something that can be passed to the web worker (causing the error that you have run into), and you will need to provide the necessary methods/functions to the objects on the web worker's side of the environment, and make sure they are not part of the object that is passed to the web worker(s).

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

回答by bennedich

As you suspected objects with functions cannot be posted. The same goes for objects with recursive references, but this has changed in some browsers lately. Instead of risking doing manual and costly redundant serialization for every post you can perform a test at the beginning of your script to determine which functions to use for sending/receiving data.

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

I've had the same problem and solved it by moving almost all code into the worker and just keeping a renderer (wrapping the 2d context renderer) in the main thread. In the worker I serialize the different draw calls meant for the canvas into just numbers in an (typed) array. This array is then posted to the main thread.

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

So for instance when I want to draw an image I invoke the drawImage()method on my worker renderer instance in the worker. The call is translated into something like [13,1,50,40]which corresponds to the draw method enum, image unique id and its xy coordinates. Multiple calls are buffered and put in the same array. At the end of the update loop the array is posted to the main thread. The receiving main renderer instance parses the array and perform the appropriate draw calls.

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

回答by xuanji

I recently encountered this same problem when using web workers. Anything I passed to my worker kept all its properties but mysteriously lost all its methods.

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

You will have to define the methods in the web worker script itself. One workaround is to importScriptsthe class definition and manually set the __proto__property of anything you receive. In my case I wanted to pass a gridobject, defined in grid.js(yup, I was working on 2048), and did it like so:

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

importScripts('grid.js')

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

回答by José Cabo

The real problem with object and webworkers is with the methods of that objects. A object should not have methods just properties.

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

Ex:

前任:

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


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

The first wont work (with the mentioned error message) with postMessage and the second will work.

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

回答by Philipp Cla?en

When you pass data to a web worker, a copy of the data is made with the structured clone algorithm. It is specified in HTML5 (see § 2.9: Safe passing of structured data).

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

MDN has an overview of supported types. As functions are not supported, trying to clone objects containing functions will therefore throw a DATA_CLONE_ERRexception.

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

What to do if you have an object with functions?

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

  • If the functions are not relevant, try to create a new object that contains only the data that you want to transfer. As long as you use only supported types, send should work. Using JSON.stringifyand JSON.parsecan also be used as a workaround, as stringifyignores functions.

  • If the functions are relevant, there is no portable way. There are attempts to use a combination of toStringand eval(e.g., used by the jsonfslibrary), but this will not work in all cases. For instances, it will break if your function is native code. Also closures are problematic.

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

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

回答by vadimk

take a look at the vkThreadplugin

看看vkThread插件

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

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

it can pass function to a worker, including function with context ( object's method ). It can also pass functions with dependencies, anonymous functions and lambdas.

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

--Vadim

--瓦迪姆

回答by julian libor

Some type of objects like ArrayBuffer and ImageBitmap which have the Transferableinterface implementet and can be transfered without copy the Object.

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

Thats very usefull in Context of Canvas + Web worker cause you can save the time of copy the data between the threads.

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

回答by Shruthi Prakash

if you want to pass the object with methods you can stringify it and parse it at the receiving end.

如果你想用方法传递对象,你可以将它字符串化并在接收端解析它。

postMessage(JSON.stringify(yourObject)

In the listener

在听者

this.worker.addEventListener('message', (event) => {
   const currentChunk = JSON.parse(event.data);   
});