HTML webWorker

9265 ワード

一、概要
javascript言語は単一スレッドモデルを採用しています.つまり、すべてのタスクは一つのスレッドでしかできません.一回に一つのことしかできません.前の仕事が終わっていないので、後の仕事は待つしかないです.コンピューターの計算能力が強くなるにつれて、特に多核cpuの出現は、単スレッドが大きな不便をもたらし、コンピュータの計算能力を十分に発揮できなくなりました.
ウェブウォーカーの役割は、javascriptのためにマルチスレッド環境を作成し、メインスレッドがウォーカースレッドを作成し、いくつかのタスクを後者に割り当てて実行することができます.メインスレッドが動作している間、ワーカースレッドはバックグラウンドで動作し、両者は干渉しない.ウォーカースレッドが計算タスクを完了するまで、結果をメインスレッドに戻します.このような利点は、いくつかの計算集約型または高遅延タスクは、ウォーカースレッドによって負担され、メインスレッド(一般的にはuiインタラクションを担当する)がスムーズになり、ブロックされたり遅くなったりしないことである.
ウォーカースレッドは、新規作成が成功すると、常に実行されます.ユーザがボタンを押したり、フォームを提出したりして、メインスレッド上の活動に邪魔されません.このようにすれば、メインスレッドの通信にいつでも応答することができる.しかし、これはワーカーが比較的に資源を消費することをもたらして、過度に使うべきでなくて、その上いったん使ったら、閉じるべきです.
二、webWorkカーの使用上の注意点
1.同源制限
ウォーカースレッドに割り当てられたスクリプトファイルは、メインスレッドのスクリプトファイルと同じソースでなければなりません.
2.dom制限
ウォーカースレッドがあるグローバルオブジェクトは、メインスレッドとは違って、メインスレッドのあるウェブページのdomオブジェクトを読めません.document、window、parentなどのオブジェクトは使えません.しかし、ウォーカースレッドはnavigatorオブジェクトとlocationオブジェクトがあります.
3.通信連絡
ウォーカースレッドとメインスレッドは同じコンテキスト環境ではなく、直接通信できないので、メッセージを通じて完了しなければなりません.
4.スクリプト制限
ウォーカースレッドはalert()方法とconfirm()方法を実行できないが、xmlhttprequestオブジェクトを使用してajax要求を送信することができる.5.ファイル制限
ワーカースレッドはローカルファイルを読めませんでした.つまり、このマシンのファイルシステムを開けません.ロードされたスクリプトは、ネットワークから必要です.
三、基本的な使い方
1.メインスレッド
メインスレッドはnewコマンドを使用して、Worker()コンストラクションを呼び出して、Workerスレッドを新規作成します.
var worker = new Worker('work.js');
    Worker()コンストラクタのパラメータは、Workerスレッドが実行するタスクであるスクリプトファイルである.Workカーはローカルファイルを読めませんので、このスクリプトはネットワークから必要です.もしダウンロードが成功しなかったら、Workerは黙って失敗します.
次に、メインスレッドがworker.postMessage()メソッドを呼び出し、Workカーにメッセージを送る.
worker.postMessage('Hello World');
worker.postMessage({method: 'echo', args: ['Work']});
    worker.postMessage()方法のパラメータは、メインスレッドがWorkカーに送るデータです.バイナリデータを含む様々なタイプのデータがあります.
次に、メインスレッドは、worker.onmessageを介して傍受関数を指定し、サブスレッドから返信されたメッセージを受信する.
worker.onmessage = function (event) {
  console.log('Received message ' + event.data);
  doSomething();
}

function doSomething() {
  //     
  worker.postMessage('Work done!');
}
上記のコードでは、イベントオブジェクトのdata属性は、Workカーから送られてきたデータを取得することができます.
Workカーはタスクを完了したら、メインスレッドをオフにすることができます.worker.terminate()2.ウォーカースレッド
ウォーカースレッドの内部には、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()方法は、マスタスレッドにメッセージを送信するために使用される.
メインスレッドから送られてきたデータによって、Workerスレッドは異なる方法を呼び出すことができます.
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);
3.ワードローディングスクリプト
Workカーの内部に他のスクリプトをロードする場合、専用の方法があります.
importScripts('script1.js');
この方法は複数のスクリプトを同時にロードすることができます.
importScripts('script1.js', 'script2.js');
4.エラー処理
メインスレッドはWorkカーにエラーが発生しているかどうかを監視できます.エラーが発生すると、WorkカーはメインスレッドのimportScripts()イベントをトリガする.
worker.onerror(function (event) {
  console.log([
    'ERROR: Line ', e.lineno, ' in ', e.filename, ': ', e.message
  ].join(''));
});

//   
worker.addEventListener('error', function (event) {
  // ...
});
Workカー内部でもerror事件を傍受することができる.
5.ウォーカーを閉じる
使い終わったら、システムの資源を節約するために、Workerを閉じなければなりません.
//    
worker.terminate();

// Worker   
self.close();
四、データ通信
メインスレッドとワーカーの間の通信内容は、テキストでもいいし、オブジェクトでもいいです.なお、このような通信は、発信元ではなくコピー関係であり、ワーカーが通信内容に対して修正したものであり、主スレッドに影響を与えない.実際、ブラウザ内部の動作メカニズムは、まず通信内容をシリアル化し、シリアル化した文字列をWorkカーに送り、後者は元に戻すことです.
//    
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);
};
しかし、コピー方式でバイナリデータを送信すると、性能に問題があります.例えば、メインストリームはWorkカーに500 MBのファイルを送信します.デフォルトではブラウザは元のファイルのコピーを作成します.この問題を解決するために、JavaScriptは、メインスレッドがバイナリデータを直接にサブスレッドに転送することを許可していますが、一旦移行すると、メインスレッドはこれらのバイナリデータをもう使えなくなります.このようなデータの転送方法は、Transferable Objectsといいます.これにより、メインスレッドが速くWorkカーにデータを渡すことができ、映像処理、音声処理、3 D演算などに便利になり、性能に負担がかかりません.
データの制御権を直接移行するには、次のような書き方が必要です.
// Transferable Objects   
worker.postMessage(arrayBuffer, [arrayBuffer]);

//   
var ab = new ArrayBuffer(1);
worker.postMessage(ab, [ab]);
五、例:ウォーカースレッド完成ポーリング
  ,            ,            。         Worker   。
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');
     ,Worker          ,        。     ,            ,         。
六、例:ワーカーの新しいワーカー
Worker           Worker   (     Firefox      )。                ,   10  Worker。

       。


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


// 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!
}
     ,Worker        10  Worker   ,      10  Worker     ,           。           。
// 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
1.メインスレッド
ブラウザの原生はerror構造関数を提供して、メインスレッドのWorkerスレッドを生成するために使用します.
var myWorker = new Worker(jsUrl, options);
Worker()コンストラクタは、2つのパラメータを受け入れることができます.最初のパラメータはスクリプトのURLです.このパラメータは必要です.JSスクリプトをロードするしかないです.そうでないとエラーが発生します.第二のパラメータは、設定オブジェクトであり、オブジェクトは選択可能である.一つの役割は、Workカーの名前を指定して、複数のWorkerスレッドを区別することです.
//    
var myWorker = new Worker('worker.js', { name : 'myWorker' });

// Worker   
self.name // myWorker
    Worker()コンストラクタは、メインスレッドの動作ウォーカーのためにWorkerオブジェクトを返す.Workカースレッドオブジェクトの属性と方法は以下の通りです.
Worker.onerror:   error        。
Worker.onmessage:   message        ,        Event.data   。
Worker.onmessageerror:   messageerror        。               ,       。
Worker.postMessage():  Worker       。
Worker.terminate():     Worker   。
2.ウォーカースレッド
Web Workカーは、自分のグローバルオブジェクトを持っています.メインスレッドの    Worker()ではなく、Workカーのためにカスタマイズされたグローバルオブジェクトです.したがって、window上で定義されているオブジェクトおよび方法はすべて使用できるわけではない.
Workカースレッドには自分のグローバル属性と方法があります.
self.name: Worker    。     ,       。
self.onmessage:  message       。
self.onmessageerror:   messageerror        。               ,       。
self.close():   Worker   。
self.postMessage():      Worker       。
self.importScripts():   JS   。
 原文の住所:http://www.ruanyifeng.com/blog/2018/07/web-worker.html