Web Workerとは
UIスレッドとは別のスレッドに処理を移行し、バックグラウンドで実行するための仕組み。
UIスレッドの描画を阻害することなく、実行時間を要するタスクを処理することができます。
Web Workerの使い方
参考文献を頼りに、Web Workerを使ってメインスレッドと別スレッド(以下ワーカースレッド)間でメッセージを送り合う処理を書きました。
まずは全体のソースから。
index.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> <meta name="viewport" content="width=device-width" /> <title>Web Worker</title> </head> <body> <h1>Hello, Web Worker.<h1> <script src="script.js"></script> </body> </html>
script.js
'use strict'; // // メインスレッド上の処理 // // ブラウザがWeb Workerをサポートしている場合のみ処理実行 if (window.Worker){ // Workerオブジェクト let worker = new Worker('worker.js'); // ワーカースレッド上で非同期に実行されるイベントハンドラ // ワーカースレッド上のWorker::postMessage()で発火する worker.addEventListener('message', function(e){ console.log(e.data); }, false); // doWork.jsで登録したイベントハンドラが発火する worker.postMessage('Hello, Web Worker!'); }
worker.js
// // ワーカースレッド上の処理 // // ワーカースレッド上で非同期に実行されるイベントハンドラ // メインスレッド上のWorker::postMessage()で発火する self.addEventListener('message', function(e){ self.postMessage(e.data); });
Workerの生成
// script.js let worker = new Worker('worker.js');
new Worker('script.js')
でスクリプト'script.js'内の処理を実行するワーカーオブジェクトを生成します。
(script.js
は同一生成元ポリシに従うので注意)
メインスレッドからpostMessage()された時の処理の登録
// worker.js self.addEventListener('message', function(e){ self.postMessage(e.data); });
Main→Worker でメッセージが来たときの処理をaddEventListenr
に登録します。
ちなみに、このイベントハンドラは以下のようにしても登録することができます(が、Googleのドキュメントでは上記を推奨しています)。
onmessage = function(e) { self.postMessage(e.data); };
ワーカースレッドからpostMessage()された時の処理の登録
// script.js worker.addEventListener('message', function(e){ console.log(e.data); }, false);
Worker→ でメッセージが来たときの処理をaddEventListenr
に登録します。
今回は返ってきたメッセージをコンソール出力するだけ。
メインスレッドからワーカースレッドへメッセージ送信
// script.js worker.postMessage('Hello, Web Worker!');
この処理によってworker.jsで登録したイベントハンドラ→script.jsで登録したイベントハンドラの順に処理が走ります。
上手くいきました。
Web Workerの特徴
直接DOM操作はできない
Web Workerは直接のDOM操作が許可されていません。ワーカースレッドがどうしてもDOM操作を行いたい場合、メインスレッドにDOMへのアクセスをお願いするなど、一工夫必要になります。
window
オブジェクトの一部プロパティを使用できない
Worker自体が通常のスクリプトとは異なるグローバルコンテキストから呼び出されるため、普通のスクリプトのようにwindow
オブジェクトを参照できません(DedicatedWorkerGlobalScope と呼ばれるコンテキストで実行されます)。
Web Workerの種類
Web Workerにも幾つか種類があります。
Dedicated Worker
今回例として紹介したWorker。呼び出し元のスクリプトのみが参照できます。
複数のスクリプトから一つのWorkerオブジェクトを参照したい場合、次項のShared Workerを利用する必要があります。
Shared Worker
異なるwindow
をグローバルコンテキストとする複数のスクリプトから利用できるWorker。ただし、各スクリプトは同一ドメイン内にある必要があります。
ServiceWorker
オフライン上でのユーザ体験向上を実現するための特殊なWorker。複数アプリ間・ブラウザ間・ネットワーク間のプロキシ機能を提供します。例えばネットワークのオンライン・オフラインの状況によって、クライアントに返戻するリクエスト結果を変えたりすることができるほか、プッシュ通知やバックグラウンド同期のAPIも利用することができます。Googleの提唱するPWAで用いられるWorkerでもあります。
Chrome Worker
Firefoxがアドオン開発時にWebWorkerを利用したいとき・js-ctypesを使いたいときに利用するWorker。
Audio Worker
音声処理をWorker内で実行したい時に使います。
参考文献
https://www.html5rocks.com/ja/tutorials/workers/basics/
Web Workers API - Web API インターフェイス | MDN