ジャバスクリプト:ウェブワーカー

原文章:https://wangdoc.com/javascript/index.html

ウェブワーカー

アウトライン

JavaScript言語は、すべてのタスクが唯一のスレッドで完了することができますされ、シングルスレッドモデルを、使用して、あなただけの一つのことを行うことができます。タスクの先行が行われていない、後者のタスクは待つことができます。コンピューティング・パワーを増加し、特にマルチコアCPUの出現は、不便大量のではなく、完全なコンピューティングパワーをシングルスレッドで。

ウェブワーカーの役割は、メインスレッドがワーカースレッドを作成し、後者は実行するためにいくつかのタスクを割り当てますことができますJavaScriptのためのマルチスレッド環境を作成することです。メインスレッドの実行中に、バックグラウンドで実行されているワーカースレッドは、2つの非干渉。コンピューティングタスクを完了するために、ワーカースレッドまで待ってから、メインスレッドに結果を返します。利点は、いくつかの高遅延や計算集約型のタスクが滑らかで、ブロックされていない維持するために、ワーカースレッドの実行、(UIの相互作用のために、通常は責任を負う)メインスレッドに引き渡さまたはスローダウンすることができるということです。

(ユーザーがフォームを送信するボタンをクリックするなど)、メインスレッド上で新しい成功一度ワーカースレッドは、それが常に実行され、アクティブになりません中断。これは、メインスレッドに応じて、任意の時点での通信を容易にします。しかし、それはまた、労働者がリソースを消費する原因と、過剰に使用してはならない、と一度使用した後、彼らは閉鎖されるべきです。

いくつかのWebワーカーを使用して注意を払うがあります。

(1)限界に相同

スクリプトファイルを実行するために割り当てられたワーカースレッドは、スクリプトファイルには、メインスレッドと相同でなければなりません。

(2)DOM制限

ワーカースレッドグローバルなオブジェクトが配置され、メインスレッドが同じではありませんが、DOMオブジェクトは、メインスレッドが使用できないページを読むことができないdocumentwindowparentこれらのオブジェクトは。しかし、ワーカースレッドが使用できるnavigatorオブジェクトとlocationオブジェクトを。

(3)グローバルオブジェクトの制限

労働者のグローバルオブジェクトはWorkerGlobalScope、グローバルオブジェクトのページとは異なりWindow、多くのインターフェイスを取得します。例えば、理論的にワーカースレッドを使用することができないconsole.log規格が存在ワーカーグローバル・オブジェクトの言及がないため、consoleインターフェイスのみ定義NavigatorインターフェイスとLocationインターフェイスを。しかし、ブラウザが実際にワーカースレッドをサポートconsole.log、保険の練習を、このメソッドを使用することではありません。

(4)通信リンク

ワーカースレッドとメインスレッドは、メッセージを介して行う必要があり、同じコンテキストで、それらは直接通信することができないではありません。

(5)スクリプト制限

ワーカースレッドが実行できないalert()方法およびconfirm()方法を、それがAJAXリクエストXMLHttpRequestオブジェクトを使用してもよいです。

(6)ファイルの制限

ワーカースレッドが(マシン・ファイル・システムをオンにすることはできませんローカルファイルを読み取ることができませんでしたfile://)、それはスクリプトをロードし、それがネットワークから来なければなりません。

基本的な使い方

メインスレッド

メインスレッドが使用するnew呼び出し、コマンドをWorker()新しいワーカースレッドを作成するためにコンストラクタを。

var worker = new Worker('work.js');

Worker()コンストラクタの引数は、実行するワーカースレッドのタスクでスクリプトファイルです。労働者がローカルファイルを読み取ることができないので、そのスクリプトはネットワークから来なければなりません。ダウンロードが(例えば、404)に成功していない場合は、労働者が黙って失敗します。

次に、メインスレッドは、呼び出しworker.postMessage()方法、作業者にメッセージを。

worker.postMessage('Hello World');
worker.postMessage({method: 'echo', args: ['Work']});

worker.postMessage()パラメータ方法は、メインスレッドは、労働者のデータを渡されます。これは、バイナリデータを含む各種データであってもよいです。

次に、スルーメインスレッドworker.onmessage指定のリスナー関数は、メッセージを受信すると、子スレッドを送り返します。

worker.onmessage = function (event) {
  doSomething(event.data);
}

function doSomething() {
  // 执行任务
  worker.postMessage('Work done!');
}

上記のコードでは、イベントオブジェクトのdataプロパティには、作業者が送信されたデータを取得することができます。

労働者がタスクを完了するためにした後、メインスレッドは、それをオフにすることができます。

worker.terminate();

ワーカースレッド

ワーカー雌ねじは、モニタ機能を持って監視する必要があるmessageイベントを。

self.addEventListener('message', function (e) {
  self.postMessage('You said: ' + e.data);
}, false);

上記のコード、self子スレッド自体の代わりに、すなわち、サブスレッドグローバルオブジェクト。したがって、書き込み、次の2種類と同等です。

// 写法一
this.addEventListener('message', function (e) {
  this.postMessage('You said: ' + e.data);
}, false);

// 写法二
addEventListener('message', function (e) {
  postMessage('You said: ' + e.data);
}, false);

使用に加えて、self.addEventListener()指定された監視機能を使用することも可能でself.onmessage指定します。パラメータモニタ機能は、そのイベントオブジェクトであるdataプロパティメインスレッドによって送信されたデータを含みます。self.postMessage()メインスレッドにメッセージを送信するための方法。

メインスレッドに送信されたデータは、ワーカースレッドが異なるメソッドを呼び出すことができ、以下では一例です。

self.addEventListener('message', function (e) {
  var data = e.data;
  switch (data.cmd) {
    case 'start':
      self.postMessage('WORKER STARTED: ' + data.msg);
      break;
    case 'stop':
      self.postMessage('WORKER STOPPED: ' + data.msg);
      self.close(); // Terminates the worker.
      break;
    default:
      self.postMessage('Unknown command: ' + data.msg);
  };
}, false);

上記のコードでは、self.close()内部労働者自体を閉鎖します。

ワーカーロード・スクリプト

あなたは、追加のスクリプトをロードしたい場合は、内部労働者は、特別な方法がありますimportScripts()

importScripts('script1.js');

この方法は、同時に複数のスクリプトを読み込むことができます。

importScripts('script1.js', 'script2.js');

エラー処理

メインスレッドは、ワーカー・エラーが発生したかどうかを監視することができます。エラーが発生した場合、労働者は、のメインスレッドトリガーするerrorイベントを。

worker.onerror(function (event) {
  console.log([
    'ERROR: Line ', event.lineno, ' in ', event.filename, ': ', event.message
  ].join(''));
});

// 或者
worker.addEventListener('error', function (event) {
  // ...
});

労働者は、内部監視できるerrorイベントを。

閉じるワーカー

使用後は、節約システムリソースへのためには、労働者閉じる必要があります。

// 主线程
worker.terminate();

// Worker 线程
self.close();

データ通信

上述したように、メインスレッドとワーカー間の通信は、テキストとすることができる、またはオブジェクトであってもよいです。メインスレッドには影響しません値ではなく、労働者、パスによる通信の内容を変更し、あること、これは通信関係のコピーであることに留意すべきです。作業者は、それを復元した、シリアル化に実際には、ブラウザ、第一の通信コンテンツシリアライザ内部の動作機構は、文字列が次に送信されます。

ワーカースレッド、また、ファイル、BLOB、ArrayBuffer他のタイプとしてメイン交換バイナリデータ、間、スレッド間で送信されても​​よいです。ここでは一例です。

// 主线程
var uInt8Array = new Uint8Array(new ArrayBuffer(10));
for (var i = 0; i < uInt8Array.length; ++i) {
  uInt8Array[i] = i * 2; // [0, 2, 4, 6, 8,...]
}
worker.postMessage(uInt8Array);

// Worker 线程
self.onmessage = function (e) {
  var uInt8Array = e.data;
  postMessage('Inside worker.js: uInt8Array.toString() = ' + uInt8Array.toString());
  postMessage('Inside worker.js: uInt8Array.byteLength = ' + uInt8Array.byteLength);
};

ただし、パフォーマンス上の問題を引き起こす可能性があり、バイナリデータのコピーを送信します。例えば、労働者に500MBのファイルを送信するために、メインスレッド、ブラウザは、デフォルトでは、元のファイルのコピーを生成します。この問題を解決するために、JavaScriptはメインスレッドがサブスレッドに直接バイナリデータを転送することができませんが、転送された後、メインスレッドは、もはや面倒な状況データを修正するために、複数のスレッドの出現を防ぐためであるこれらのバイナリデータを、使用することができます。呼ばれるこのデータ転送方法、譲渡オブジェクトこれは、メインスレッドがすぐに画像処理、音声処理のために、労働者にデータを置くことができることができ、3Dおよびその他の操作はありません、パフォーマンスのオーバーヘッド、非常に便利です。

あなたは、制御データの転送を指示したい場合は、以下の文言を使用する必要があります。

// Transferable Objects 格式
worker.postMessage(arrayBuffer, [arrayBuffer]);

// 例子
var ab = new ArrayBuffer(1);
worker.postMessage(ab, [ab]);

ウェブワーカー同じページ

一般的に、労働者がロードされたスクリプトは、別のJavaScriptファイルですが、また、同じWebページコード内のメインスレッドでロードすることができます。

<!DOCTYPE html>
  <body>
    <script id="worker" type="app/worker">
      addEventListener('message', function () {
        postMessage('some message');
      }, false);
    </script>
  </body>
</html>

上記埋め込まれたスクリプト・ページの一部である、注意が指定する必要があります<script>ラベルtype属性値が認識していないブラウザで、ケースがありますapp/worker

その後、労働者に対処するために、このセクションのページに埋め込まれたスクリプトをお読みください。

var blob = new Blob([document.querySelector('#worker').textContent]);
var url = window.URL.createObjectURL(blob);
var worker = new Worker(url);

worker.onmessage = function (e) {
  // e.data === 'some message'
};

次いで、上記のコード、ページに埋め込まれた第1のスクリプトコード、バイナリオブジェクトに変換し、バイナリオブジェクトのURLを生成し、作業者がURLをロードしましょう。これは、メインスレッドと上記と同じページ上の労働者のコードを行って。

例:完全なポーリングにワーカースレッド

時には、ブラウザはその初めての状態変化つまり、サーバーの状態をポーリングする必要があります。この作品は、労働者の内部に配置することができます。

function createWorker(f) {
  var blob = new Blob(['(' + f.toString() + ')()']);
  var url = window.URL.createObjectURL(blob);
  var worker = new Worker(url);
  return worker;
}

var pollingWorker = createWorker(function (e) {
  var cache;

  function compare(new, old) { ... };

  setInterval(function () {
    fetch('/my-api-endpoint').then(function (res) {
      var data = res.json();

      if (!compare(data, cache)) {
        cache = data;
        self.postMessage(data);
      }
    })
  }, 1000)
});

pollingWorker.onmessage = function () {
  // render data
}

pollingWorker.postMessage('init');

上記のコードは、労働者のポーリングデータは、1秒に1回、その後、キャッシュと比較します。そうでない場合には、新しい変更とサーバは、そのメインスレッドに通知しなければならないことを意味します。

例:労働者の新しいワーカー

内部ワーカーワーカースレッドは、新しいスレッド(現在はFirefoxブラウザでサポートされている)を作成することができます。次の例では、計算集約的なタスク、作業者に割り当てられた10です。

メインスレッドのコードは次の通りです。

var worker = new Worker('worker.js');
worker.onmessage = function (event) {
  document.getElementById('result').textContent = event.data;
};

ワーカースレッドのコードは次のようです。

// worker.js

// settings
var num_workers = 10;
var items_per_worker = 1000000;

// start the workers
var result = 0;
var pending_workers = num_workers;
for (var i = 0; i < num_workers; i += 1) {
  var worker = new Worker('core.js');
  worker.postMessage(i * items_per_worker);
  worker.postMessage((i + 1) * items_per_worker);
  worker.onmessage = storeResult;
}

// handle the results
function storeResult(event) {
  result += event.data;
  pending_workers -= 1;
  if (pending_workers <= 0)
    postMessage(result); // finished!
}

上記のコードでは、ワーカーワーカー内蔵雌ねじ10をスレッド、順次開始と終了の計算を通知するために、労働者10へこのメッセージを送信します。次のようなタスクのスクリプトコードを計算することです。

// core.js
var start;
onmessage = getStart;
function getStart(event) {
  start = event.data;
  onmessage = getEnd;
}

var end;
function getEnd(event) {
  end = event.data;
  onmessage = null;
  work();
}

function work() {
  var result = 0;
  for (var i = start; i < end; i += 1) {
    // perform some complex calculation here
    result += 1;
  }
  postMessage(result);
  close();
}

API

メインスレッド

でブラウザのネイティブWorker()ワーカースレッドのために作成するために、メインスレッドのコンストラクタ。

var myWorker = new Worker(jsUrl, options);

Worker()コンストラクタは、2つのパラメータを受け入れることができます。最初のパラメータは、それ以外の場合はエラーになり、スクリプトのURL(同一生成元ポリシーを遵守しなければならない)、このパラメータが必要とされており、唯一のJSスクリプトをロードすることができます。第2のパラメータは、構成オブジェクトのオプションです。その役割は、複数のワーカースレッドを区別するために使用され、労働者の名前を指定することです。

// 主线程
var myWorker = new Worker('worker.js', { name : 'myWorker' });

// Worker 线程
self.name // myWorker

Worker()コンストラクタは、メインスレッドが操作ワーカーのために使用される、ワーカースレッドオブジェクトを返します。ワーカースレッドオブジェクトのプロパティとメソッド次の通りです。

  • Worker.onerror:指定リスナー関数のエラーイベント。
  • Worker.onmessage:指定したメッセージのイベントリスナー関数は、データが送信されるからEvent.dataプロパティ。
  • Worker.onmessageerror:指定リスナー関数messageerrorイベント。送信データを文字列にシリアライズすることができない場合は、このイベントをトリガします。
  • Worker.postMessage():ワーカースレッドにメッセージを送信します。
  • Worker.terminate():ワーカースレッドの即時終了。

ワーカースレッド

ウェブワーカーは、独自のグローバルオブジェクトではなく、メインスレッドを持っているwindowが、労働者、グローバルオブジェクトのために特別に調整します。このように定義されたwindow上記のすべてのオブジェクトおよびメソッドを使用しません。

ワーカースレッドは、独自のグローバルプロパティとメソッドのいくつかを持っています。

  • self.name:労働者の名前。コンストラクタで指定されたこの読み取り専用属性、。
  • self.onmessage:指定messageリスナー関数イベント。
  • self.onmessageerror:リスナー関数messageerrorイベントを指定します。送信データを文字列にシリアライズすることができない場合は、このイベントをトリガします。
  • self.close():閉じるワーカースレッド。
  • self.postMessage():ワーカースレッドを生成するためにメッセージを送信します。
  • self.importScripts():ロードJSスクリプト。

(終わり)

おすすめ

転載: www.cnblogs.com/wbyixx/p/12499586.html