[JavaScript/MultiThread]WebWorkerを使う
概要
Web Workerについて学ぶきっかけは以下のように想定されます。
- JavaScriptのクライアントサイドでマルチスレッドのプログラムを実行する方法を探していた。
- OSSのソースコードやサンプルなどでWorkerをみかけ、それについて調べていた。
- MDNのWebAPIについて順次調べていた。
- その他。
どの経緯にしてもMDNのドキュメントを読むのが最善でしょう。
しかし、ずっしりと分厚い内容を一つずつかみ砕くのが大変なのは間違いありません。
そこで2020年03月11日でMDNのWebWorkerのに解説されている内容をまとめてみました。
主要な目的は自分の学習であるものの、誰かの役に立ってくれると尚幸いです。
Web Workers API - Web API | MDN
https://developer.mozilla.org/ja/docs/Web/API/Web_Workers_API
注意事項
WebAPIには名前の近しいAPIとしてServiceWorkerがリストに並んでいます。
ServiceWorkerはWebWorkerの拡張で、別物ではありません。
今回は限定的にWobWorkerAPIの範疇のみを扱います。
また、APIの使用可否や注意についてはChromeを基準にしています。
(あくまで自分の覚書のためです)
Web Worker 基礎知識
活用の目的
主に以下の四つの目的で利用される。
- 計算処理の高速化
- 分散処理のシミュレーション
- 非同期的監視処理
- タスク的処理
Workerはマルチスレッド処理であるため、
描画に使われるメインスレッドから関連しない処理を分離することで高速化を図ることができます。
待ち受け時間が長い処理についても、その監視を分離することに異論はないはずです。
Workerが備えているマルチスレッドで実行される処理は、
タスク処理とも言い換えることができます。
マルチスレッドについて十分に知識があるエンジニアであれば、タスク・プロセッサ的に扱う事で可読性の向上などにつなげる事もできるはずです。
Web Workerの種類
Web Workerには複数の種類があります。
- Dedicated Worker (専用ワーカー)
- Shared Worker (共有ワーカー)
- Service Worker
- Audio Worker
- Chrome Worker
Dedicated Worker
今回主に扱うWorkerです。
特有の URL で動作する専用ワーカーのインスタンスを生成することができます。
コンテキストとしてDedicatedWorkerGlobalScope
を保持しています。
Shared Worker
iframeなどの異なるwindowで実行されている複数のスクリプトから利用できるWorkerです。
コンテキストを共有するためSharedWorkerGlobalScope
を使用します。
Dedicatedより複雑な下準備と手順を必要とします。
今回は触れません。
Service Worker
オフラインでのユーザーエクスペリエンスを実現するために設計されています。
ServiceWorkerは主にアプリケーションが通信等を行う際に噛ませるプロキシとして使います。
サーバ上のリソースの更新も担います。
Service Worker を使うことで、プッシュ通知やバックグラウンド同期の API も利用可能になります。
今回は触れません。
Audio Worker
音声処理を Worker のコンテキスト内でスクリプトで直接実行する能力を提供します。
Chrome Worker
Chrome Worker は Firefox 上でのみ使える Worker です。
今回は触れません。
活用場面
Web Workers が使用できる関数とクラス - Web API | MDN
https://developer.mozilla.org/ja/docs/Web/API/Web_Workers_API/Functions_and_classes_available_to_workers
Workerはマルチスレッドの機能です。
そのため、利用が想定されている機能と、そうでない機能があります。
- 利用が想定されている機能
- 通信の監視や管理
- WebSocket
- XMLHttpRequest
- Fetch
- ストレージアクセスの監視や管理
- IndexedDB
- 通信の監視や管理
- 使えない場面
- UI(DOM)の表示に関わる処理
- TextEncoder API
- ImageData API(Canvas要素)
- WEB GL API
- Workerの孫生成
- 利用に注意が必要な機能
- コンテキスト間の通信
- BroadcastChannelAPI(非対応)
- ChannelMessaginAPI(対応)
- URL API(利用に手順あり)
- コンテキスト間の通信
スレッド間のデータ送受信
データの送信postMessage()
メソッド
データの受信onmessage
プロパティ
これらを使ってメッセージとデータをやり取りできます。
なお、送信したデータは原則的に受取先でコピーされます。(特にメッセージ文字列等)
Transferable
を実装されたデータについてはpostMessage()
で渡してもコピーしません。
Transferableを実装されたクラスは以下があります。
ArrayBuffer
, ImageBitmap
, MessagePort
, OffscreenCanvas
Dedicated Worker の活用
Workerの機能概要
非常にシンプルに、最小限の形で作られています。
Worker - Web API | MDN
https://developer.mozilla.org/ja/docs/Web/API/Worker
- Constructor
- Worker() : Workerインスタンスの立ち上げとタスクの読み込み
- Method
- postMessage():インスタンスへのメッセージ
- terminate():インスタンスの強制終了
- Event Handler
- onerror:インスタンスでエラーが発生した際のイベント
- onmessage:インスタンスがメッセージを受信した際のイベント
- onmessageerror:インスタンスが処理できないメッセージを受信した場合のイベント
Worker()
const script_url = "http://script_url.js";
const option = {
type:"module", // "classic" | "module"
credentials:"", // "omit" | "same-origin" | "include"
name:"worker_01",
};
const worker = new Worker(script_url, option);
Workerコンストラクタに関するメモ
- Workerに渡すスクリプトは同一生成元の必要がある。(クロスオリジンは不可)
- Workerに渡すスクリプトのMIMEタイプは、常に一つ以上が
text/javascript
でなければならない。 - optionのtypeはWorkerのトップレベルスクリプトとしてES Moduleを使用するかどうか。
- optionのnameはデバッグに有用
- WorkerとES Moduleのimportについてはこちらを参照。
Chrome 80 から Web Worker (Dedicated Worker) で ES Modules が使えます
https://nhiroki.jp/2019/12/05/es-modules-for-dedicated-workers