SharedWorkerというWeb Workerがあります。
よく使うWeb Worker(new Worker(...)
)をDedicated(専用)Workerと呼ぶのに対し、SharedWorker(new SharedWorker(...)
)はShared(共有)Workerと呼びます。
Sから始まるWorkerでService Workerというものもありますが、これとは全くの別物です。
SharedWorkerは、複数のウィンドウやタブを開いたときでもスレッドが共有され、各ウィンドウとはメッセージで情報を共有することができます。
これを使うことで、WebSocketなどを使っている場合に各ウィンドウからコネクションを生やさずに、SharedWorker経由の1つのコネクションで済ませるという手法があります。
ところで、iOS 16.1のWebViewで利用するとクラッシュします。(ref)
SharedWorkerを使っているのは誰だ
突如、iOS16.1のみWebViewがクラッシュするとわかり、調べるとSharedWorkerが悪いとわかりました。
自身のコードの中ではSharedWorkerを使っていないのになぜでしょうか。
ほんとうにSharedWorkerを使っているか確認する
Google Chrome (Chromium)ブラウザのDeveloper ToolsのPerformanceタブを利用することで、Worker含め、どのような関数が実行されたかなどを閲覧できます。
関数からコード片を確認することもできます。
SharedWorkerを初期化しているひとを探す
実際にSharedWorkerを使っていることがわかりました。次は実際に初期化しているコードを探します。
SafariのWeb development toolsには、HTTPリクエスト/レスポンスの上書き機能があります。
Networkタブからリソースを選択、右クリックしコンテキストメニューから「リクエスト(レスポンス)のローカルオーバーライドを作成」します。
ここで最初に読み込まれるHTMLへJavaScriptを注入します。どのJavaScriptよりも早く読み込みたいのでheadの開始タグ直後などがいいでしょう。
<!DOCTYPE html>
<html lang="ja">
<head>
<script>
(() => {
const Original = window.SharedWorker;
window.SharedWorker = class Override extends SharedWorker {
constructor(...args) {
super(...args);
console.trace(args);
debugger;
}
}
})();
</script>
<meta charset="utf-8">
...
これにより、 new SharedWorker('...')
されるときに、そのスタックトレースを確認できるようになります。
Blob
上のコードを挿し込んでもわからなかったり、スクリプト自体がBlob URLだったりします。なのでBlobも同様にスタックトレースを確認します。
<script>
(() => {
const Original = window.Blob;
window.Blob = class Override extends Original {
constructor(...args) {
super(...args);
console.trace(args);
debugger;
}
}
})();
</script>
これでどのようなコードが誰によって埋め込まれているか確認できました。
Blob URLを使うことで、same-origin制約を無視してWorkerを初期化することができるようになります。
まとめ
- ChromeのDeveloper Tools、PerformanceタブでWorkerなどがどのようなコード(関数)を実行しているかタイムラインで確認できる
- SafariのWeb development tools、Networkタブでリクエストおよびレスポンスを上書きして動作確認できる
- クラスインスタンスの初期化時に処理を挟む場合対象クラスをextendsするとよい
- Blob URLを用いたWorkerの初期化はよくある