web-dev-qa-db-ja.com

Web WorkerでDOM要素から作成する方法はありますか?

コンテキスト:巨大なログファイルを処理して表示するWebアプリケーションがあります。通常、これらの行の長さは約10万行ですが、最大で400万行以上になる場合があります。そのログファイル(ユーザーが開始したものとJavaScriptの両方)をスクロールし、適切なパフォーマンスで行をフィルター処理できるように、データが到着したらすぐに各行にDOM要素を作成します(ajax経由のJSON)。これは、バックエンドでHTMLを構築するよりもパフォーマンスの点で優れていることがわかりました。その後、要素を配列に保存し、表示されている行のみを表示します。

最大100k行の場合、これには数秒しかかかりませんが、500,000行の場合はそれ以上(ダウンロードを含まない)で最大1分かかります。パフォーマンスをさらに向上させたかったので、HTML5 Web Workersを使用してみました。現在の問題は、DOMの外部であっても、Web Workerで要素を作成できないことです。そのため、Web WorkersではjsonからHTMLへの変換のみを行い、結果をメインスレッドに送信しました。そこで作成され、配列に保存されます。残念ながら、これによりパフォーマンスが低下し、現在では少なくとも30秒かかります。

質問: WebワーカーでDOMツリーの外にDOM要素を作成する方法はありますか?そうでない場合は、なぜですか?要素の作成は問題なく並行して行われる可能性があるため、これは並行性の問題を作成できないように思われます。

40

さて、@ Bergiが提供した情報を使ってさらに調査を行ったところ、W3Cメーリングリストで次の議論が見つかりました。

http://w3-org.9356.n7.nabble.com/Limited-DOM-in-Web-Workers-td44284.html

そして、Web WorkerにXMLパーサーまたはDOMパーサーへのアクセスがない理由に答える抜粋:

あなたは、DOM実装コードのいずれも、いかなる種類の非DOMオブジェクトも使用しない、または、それらのオブジェクトが完全にスレッドセーフであると仮定しています。少なくともGeckoでは、そうではありません。

この場合の問題は、複数のスレッドで同じDOMオブジェクトが影響を受けることではありません。問題は、異なるスレッド上の2つのDOMオブジェクトが両方ともグローバルな3番目のオブジェクトに接触することです。

たとえば、XMLパーサーは、Geckoではメインスレッドでしか実行できないことをいくつか行う必要があります(DTDの読み込み、オフハンド。以前に見たことがありますが、オフハンドを思い出さない他のいくつかがあります)。

ただし、言及された回避策もあります。これは、パーサーのサードパーティ実装を使用しているもので、その中の jsdom が例です。これにより、独自の個別のドキュメントにアクセスすることもできます。

16

それでは、DOMツリーの外でWeb WorkerにDOM要素を作成する方法はありますか?

番号。

何故なの?要素の作成は問題なく並行して行われる可能性があるため、これは並行性の問題を作成できないように思われます。

それらを作成するためではなく、あなたは正しい。しかし、それらをメインdocumentに追加するには、別のメモリ(blobのように)に送信する必要があります。そのため、その後ワーカーからアクセスできなくなります。ただし、 WebWorkersで使用可能なドキュメント処理はまったくありません

データが到着したらすぐに各行にDOM要素を作成します(ajax経由のJSON)。その後、要素を配列に保存し、表示されている行のみを表示します。

50万以上のDOM要素を構築するのは大変な作業です。表示されている行に対してのみDOM要素を作成してください。パフォーマンスを改善し、最初の数行をより速く表示するには、処理を小さな単位に分割し、その間にタイムアウトを使用することもできます。 激しいJavaScriptループがブラウザをフリーズさせないようにする方法 を参照してください。

11
Bergi

Webworkerの性質を理解する必要があります。特にメモリを共有している場合、スレッドを使用したプログラミングはhardです。奇妙なことが起こる可能性があります。 JavaScriptは、スレッドのようなインターリーブを処理するための機能を備えていません。

ウェブワーカーのアプローチは、共有メモリなしがあるということです。これは明らかに、DOMにアクセスできないという結論につながります。

4
Halcyon

Web WorkersからDOMに直接アクセスする方法はありません。最近@ cycle/sandboxをリリースしましたが、まだWIPですが、Cycle JSアーキテクチャを使用すると、Web WorkerでUIの動作を宣言するのはかなり簡単です。実際のDOMはメインスレッドでのみ変更されますが、イベントリスナーとDOM更新はワーカーで間接的に宣言され、リスナーで何かが発生すると合成イベントオブジェクトが送信されます。さらに、これらのサンドボックス化されたサイクルコンポーネントを通常のサイクルコンポーネントと並べて取り付けることは簡単です。

http://github.com/aronallen/-cycle-sandbox/

4
Aron Allen

Webワーカーを使用してhtml文字列を構築できない理由はわかりません。しかし、パフォーマンスが大幅に向上するとは思いません。

これはWeb-Workersとは関係ありませんが、解決しようとしている問題に関係しています。スピードアップに役立つ可能性のあるものを次に示します。

  1. DocumentFragmentsを使用します。データが入ってくるときにそれらに要素を追加し、一定の間隔(1秒に1回など)でフラグメントをDOMに追加します。この方法では、テキストの行がロードされるたびにDOMに触れる(および再描画する)必要がありません。

  2. バックグラウンドで読み込みを行い、ユーザーがスクロール領域の下部にヒットしたときにのみ行を解析します。

2
posit labs

https://developer.mozilla.org/en-US/docs/Web/Guide/Performance/Using_web_workers によると、残念ながらWebワーカーからDOMにアクセスすることはできません。

1
Strille

デザインにはいくつかのアンチパターンがあります。

  1. DOMオブジェクトの作成にはかなりのオーバーヘッドがあり、潜在的に何百万ものオブジェクトを一度に作成しています
  2. WebワーカーにDOMを管理させることは、Webワーカーがまさにではなくであるということです。 DOMイベントループが応答性を維持するように、他のすべてを実行します。

カーソルパターンを使用して、任意に大きいデータセットをスクロールできます。

  1. DOMは、開始位置と要求された行数(カーソル)でワーカーにメッセージを投稿します。
  2. Webワーカーは、ログにランダムアクセスし、取得した行(カーソルデータ)をポストバックします。
  3. DOMは、非同期カーソル応答イベントで要素を更新します。

このようにして、DOMの代わりにフェッチ中にイベントループがブロックされるワーカーによって重いリフティングが行われ、幸せな非ブロックユーザーがすべてのアニメーションがどれだけスムーズであるかに驚嘆します。

1

そのため、WebworkerでDOMを直接作成することはできません-ただし、メインスレッドの外部でかなりの処理を行う別のオプションがあるかもしれません。

作成したばかりのこのjsPerfを確認してください。 http://jsperf.com/dom-construction-obj-vs-str

基本的に、couldは、DOMから取得するすべての同じ値を持つPOJSOを発行し、メッセージを受信した後にそれをDOMオブジェクトに変換します(これは結局、HTMLを取り戻すときに何をしているのか、それ以上の文字列処理を必要としないため、POJSOはオーバーヘッドが低いだけです。このようにして、イベントリスナーなどを発行することさえできます(たとえば、イベント名の前に '!'を付け、値マップをテンプレートが提供するビュー引数にマップすることによって)。

一方、DOMパーサーを使用できない場合、テンプレートを必要に応じて変換したり、テンプレートを高速な形式にコンパイルしたりするために、独自のものが必要になります。

0
Fordi

いいえ、WebワーカーでDOM要素を作成することはできませんが、そのWebワーカーからの投稿メッセージを受け入れる関数を作成することはできます。つまり、doesはDOM要素を作成します。あなたが探しているデザインは、アレイチャッキングと呼ばれています。そして、それをWeb Workerのデザインパターンと混ぜる必要があります。

0
user316264