Works by

Ren's blog

@rennnosuke_rk 技術ブログです

【JavaScript】Web Worker

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で登録したイベントハンドラの順に処理が走ります。

f:id:rennnosukesann:20180325003901p:plain

上手くいきました。

Web Workerの特徴

直接DOM操作はできない

Web Workerは直接のDOM操作が許可されていません。ワーカースレッドがどうしてもDOM操作を行いたい場合、メインスレッドにDOMへのアクセスをお願いするなど、一工夫必要になります。

windowオブジェクトの一部プロパティを使用できない

Worker自体が通常のスクリプトとは異なるグローバルコンテキストから呼び出されるため、普通のスクリプトのようにwindowオブジェクトを参照できません(DedicatedWorkerGlobalScope と呼ばれるコンテキストで実行されます)。

WebWorkerが使用できる関数とクラス

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

Web Workers が使用できる関数とクラス - Web API インターフェイス | MDN

Web Worker を使用する - Web API インターフェイス | MDN