スクリプトを無視するWebブラウザ
「ジブン、ただのハイパーテキストのビュワーっすよ、リッチ・ウェブ・アプリケーション とかぁ、マジしんないっス、フヒヒ」
たまに Web ブラウザがそんなことを言うときがあります、というお話です。
負荷が上がるとスクリプトの実行を無視する?
Web ブラウザはまれに script を無視しているような挙動をする時があります。そんなときはエラーもなくただ処理が消滅します。ブラウザを変えると正しく動くためそれと分かります。
古めの PC ブラウザや、最近のものでもモバイルブラウザで遭遇しました。
DOM オブジェクトの大量生成など富豪な書き方をしているときに遭遇しやすいようです。また Flash と js の接続時(ExternalInterface)も注意しなくてはいけないポイントです。
これはシステムの負荷が上がるとスクリプトの実行を無視する、ということのように視えます。
しかし、それを明示している文章は寡聞にして見ません。
仮にこの推測に立つなら現象には、端末のスペック、同時に実行している他のアプリケーション、ブラウザの他のタブのコンテンツまで影響してくることになります。
これらのほとんどは Web プログラマの手の届かないことでお手上げにも思えます。
しかし現実に動いている同様な製品が存在する以上、そうも言ってられないわけで…
予防的コーディングの実施
取りうる手としては、予防的な書き方を常に実施していくことが考えられます。
- 分割可能なところで処理を中断しタイマーで再開する
- 富豪的な書き方を避け、オブジェクトの再利用を行う、GC を過信するような書き方は NG
- DOM 操作等の重そうな処理では重点的に無駄な操作がないか、チェックする
- いざ症状に遭遇したときに疑うべきところを最小にするために重そうな追加機能を辞める、または最後に回す
さて、これらのことは、Web 開発に不慣れなメンバーには難しいかも知れません…
チームに js ギークがいればいいですが、そうでないなら…泣きましょう…
1.分割可能なところで処理を中断しタイマーで再開する
予防的な書き方の最初で触れたタイマーの利用についてです。
高負荷(っぽい)なブラウザ API の処理から戻った際に、続けてすぐにアプリケーション層の処理を走らせることはせずに、タイマーにスケジュールだけをします。そして一瞬置いて実行します。
なぜこのような書き方をするか、というと…
js エンジンの内部では関数スタック・アクティベーションオブジェクト・ガベージが積みあがっていきます。
一度のコールバックで全てを終えようと無理をせず、これらの一時データをリフレッシュが済んでからタイマーで再開します。
レガシーなタイマー関数が大活躍する
このような時に使われるのが、setTimeout や setInterval といったタイマー関数です。随分古くからある関数です。
このとおり単に時計として以外にも様々な状況で利用されるべき重要な関数です。特性について習熟しておきます。
また、タイマー関数は(タイマー関数に限らず)使い辛い、書き辛いことこの上ないです。必ずラップして API を整え、さっとタイマーを挟める状態にします。
補足1
この積み上がりがどれだけシステムリソースを圧迫するか?外からはなかなか視えない上、よしんば高度な開発ツールで見えたとしても、それはあくまでその環境での話になります。所以、とりあえず予防的に書けるところは書いておけ、となります。 nopnopの日記 > フラウザごとのスタックの深さ
補足2
ただし、ユーザーのクリックイベント時にしか実行できないモバイルの音声再生や、(こちらはあまり使われませんが)別ウィンドウのポップアップなど、分割できないものもあります。(別ウィンドウはユーザーのインタラクションに際して行われないとポップアップブロックが働いてしまう)
ぺったんR フレームワークでは
ぺったんR には setTimeout をラップした X.Timer があります。
また X.EventDispatcher.prototype.asyncDispatch というイベントディスパッチをタイマー付きで行うメソッドは便利で多用しています。マジお勧め!
最後に
ブラウザの気持ちになって考える、とは度々言われることです。
フロントエンジニアを目指す人はブラウザのレンダリングエンジンや js エンジンに関する情報も都度に摂取して、ブラウザの気持ちになれるようにしましょう。
僕は Flex 案件の際に、既存の html コンテンツを再利用できるように TextFeild.htmlText を拡張したことがあります。泣きながら。知ってる人はご存知の通り、Flash の元もとの html 機能は酷くプアなものです…
その際に、Web ブラウザの気持ちがすこ~し分かった気がします。ではでは。