web-dev-qa-db-ja.com

オブジェクトをWebワーカーに渡す

PostMessage関数を介してWebワーカーにオブジェクトを渡そうとしています。
このオブジェクトは、キャンバスなどに自分自身を描くためのいくつかの機能を持つ正方形です。 Web Workerは、このオブジェクトの配列を返す必要があります。
問題は、このオブジェクトでpostMessage関数を呼び出すと、次のエラーが発生することです。

Uncaught Error: DATA_CLONE_ERR: DOM Exception 25

オブジェクトをワーカーに送信する方法と、その逆の方法の両方を取得します。
このエラーは、javascriptがオブジェクトをシリアル化する必要があるためだと思いますが、オブジェクトには関数が組み込まれているため、シリアル化できません。

誰かが同様の問題を抱えたことはありますか?これに対するいくつかの回避策を知っていますか?
前もって感謝します。

50
dgiulian

言及したエラーがスローされる理由はいくつかあります 理由はここにリストされています

オブジェクトをWebワーカーに送信するとき、オブジェクトはシリアル化され、オブジェクトがシリアル化可能なオブジェクトである場合、後でWebワーカーで非シリアル化されます。

これは、Web Workerに送信するオブジェクトのメソッドはWeb Workerに渡すことができるものではない(実行したエラーの原因になる)ため、必要なメソッド/関数をオブジェクトに提供する必要があることを意味します環境のWebワーカー側で、Webワーカーに渡されるオブジェクトの一部ではないことを確認してください。

49
erikvold

あなたが疑ったように、関数を持つオブジェクトは投稿できません。再帰的な参照を持つオブジェクトについても同じことが言えますが、最近、一部のブラウザーでこれが変更されました。すべての投稿に対して手動で費用のかかる冗長なシリアル化を行うリスクを負う代わりに、スクリプトの冒頭でテストを実行して、データの送受信に使用する機能を決定できます。

私は同じ問題を抱えており、ほとんどすべてのコードをワーカーに移動し、メインスレッドにレンダラーを保持する(2Dコンテキストレンダラーをラップする)だけで解決しました。ワーカーでは、キャンバス用のさまざまな描画呼び出しを(型指定された)配列の数字にシリアル化します。この配列は、メインスレッドにポストされます。

したがって、たとえば、イメージを描画する場合は、ワーカーのワーカーレンダラーインスタンスでdrawImage()メソッドを呼び出します。呼び出しは[13,1,50,40]のようなものに変換されます。これは、描画メソッドの列挙、画像の一意のID、およびそのxy座標に対応します。複数の呼び出しはバッファリングされ、同じ配列に入れられます。更新ループの最後に、配列がメインスレッドにポストされます。受信側のメインレンダラーインスタンスは配列を解析し、適切な描画呼び出しを実行します。

13
bennedich

最近、Web Workerを使用しているときにこの同じ問題に遭遇しました。ワーカーに渡したものはすべてそのプロパティを保持していましたが、神秘的にすべてのメソッドを失いました。

Web Workerスクリプト自体でメソッドを定義する必要があります。回避策の1つは、クラス定義をimportScriptsし、受け取ったものの__proto__プロパティを手動で設定することです。私の場合、grid.jsで定義されたgridオブジェクトを渡したい(そう、2048で作業していました)ので、次のようにしました:

importScripts('grid.js')

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

オブジェクトとウェブワーカーの本当の問題は、そのオブジェクトのメソッドにあります。オブジェクトには、プロパティだけのメソッドがあってはなりません。

例:

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


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

1つ目は(前述のエラーメッセージで)postMessageで機能せず、2つ目は機能します。

4
José Cabo

データをWebワーカーに渡すと、データのコピーが 構造化クローンアルゴリズム で作成されます。 HTML5で指定されています( §2.9:構造化データの安全な受け渡し を参照)。

MDNには サポートされているタイプの概要 があります。関数はサポートされていないため、関数を含むオブジェクトを複製しようとすると、DATA_CLONE_ERR例外がスローされます。

関数を備えたオブジェクトがある場合はどうすればいいですか?

  • 関数が関係ない場合は、転送するデータのみを含む新しいオブジェクトを作成してみてください。サポートされているタイプのみを使用している限り、送信は機能するはずです。 stringifyは関数を無視するため、 JSON.stringify および JSON.parse を回避策として使用することもできます。

  • 機能が関連している場合、移植可能な方法はありません。 toStringeval の組み合わせを使用する試みがあります(たとえば、 jsonfs ライブラリで使用されます) )が、これはすべての場合に機能するとは限りません。インスタンスの場合、関数がネイティブコードである場合は破損します。また、閉鎖には問題があります。

3
Philipp Claßen

vkThreadプラグインを見てください

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

コンテキストを持つ関数(オブジェクトのメソッド)を含む関数をワーカーに渡すことができます。また、依存関係を持つ関数、匿名関数、およびラムダを渡すこともできます。

-ヴァディム

1
vadimk

Transferable インターフェース実装を持ち、オブジェクトをコピーせずに転送できるArrayBufferやImageBitmapなどのオブジェクトのタイプ。

Canvas + Web workerのコンテキストでは非常に便利です。スレッド間でデータをコピーする時間を節約できます。

0
julian libor