とある地味なブログ

プログラミングとお絵かきに関する雑記。

RPGアツマールで、WebWorker が動かない

HTML5な自作SRPGRPGアツマールに投稿してみたら、何もしてないのに動いた!

https://game.nicovideo.jp/atsumaru/games/gm4246

という感動もつかの間、Firefoxで表示するとWebWorkerがエラー吐いてゲームが止まってしまった。Chromeでは動いたのに。

Content Security Policy: ページの設定により次のリソースの読み込みをブロックしました: https://html5.nicogame.jp/games/gm4246/path/to/worker.js (“child-src 'none'”)

恥を忍んでニコニコヘルプに問い合わせを投げてみたら、丁寧な回答が得られたので。

Firefoxは現状CSP Lv2までしか実装されていない

CSP(Content Security Policy)とは、以下のことらしい。

Content Security Policy (CSP) とは、クロスサイトスクリプティング (XSS) やデータを差し込む攻撃などといった、特定の種類の攻撃を検知し、影響を軽減するために追加できるセキュリティレイヤーです。これらの攻撃はデータの窃取からサイトの改ざん、マルウェアの拡散に至るまで、様々な目的に用いられます。

Content Security Policy (CSP) - Web セキュリティ | MDN

で、なぜChromeで動いてFirefoxで動かなかったかというと、Firefoxは、このCSPがLv2までしか実装されていないとのこと。 ChromeはLv3まで実装されているのだそうだ。

Lv3では、CSPにworker-srcという設定をできるのだが、Lv2ではchild-srcしか設定できず、child-srcではiframeまで許可してしまうから、アツマールではchild-src 'none'と設定しているそう。

それなら、child-src https://html5.nicogame.jp/games/gmXXXXみたいに設定すればまあ問題ないのではと思わなくもないがめんどくさいのだろう。

WebWorkerの代替としてのrequestIdleCallback

恥ずかしながらrequestIdleCallbackというものを初めて知った。

window.requestIdleCallback() メソッドを利用することで、ブラウザーがアイドル状態の時に実行される関数をキューに登録できます。これによりアニメーションや入力への応答など遅延が問題となる処理に影響を与えることなく、優先度の低いバックグラウンド処理をメインスレッド内で実行させられます。キューに登録された関数は、関数登録時に設定したタイムアウト時間に達していない限り、登録順に呼び出されます。

requestIdleCallback - Web API インターフェイス | MDN

ChromeFirefoxしか対応していないようなので実装状況はイマイチ。 サクッとバックグラウンド実行したいときに便利そう。

結論

WebWorkerが使えないときは、バックグラウンドで処理するのを諦めた。 敵の思考ルーチン中に画面がカクつくが、動かないよりマシなので…

ちなみに、WebWorkerが使えるかどうかは、以下のようにerrorイベントをハンドリングすることで可能。(少なくともFirefoxの場合)

const worker = new window.Worker('worker.js')
worker.addEventListener('error', (ev) => {
  console.log('使えないよ!')
});