あるHTTPレスポンスにおいて、画面の表示が遅かった(WebブラウザはIEを用いていた)。
表示時には、prototype.js(1.6.0.3)を用いて、次のようにDOMツリーを操作していた。つまり、windowオブジェクトのonloadイベントのタイミングで、DOMツリーの操作を実施していた。
Event.observe(window, 'onload', DOMツリーを操作する関数オブジェクトの参照);
つまり、次のように処理されていた(画面が二度描画されるのが、目で見て取れた)。
- WebブラウザがDOMツリーを構築する(以下、DOM構築)
- Webブラウザが画面を描画する(以下、レンダリング)
- JavaScriptによりDOMツリーを操作する(以下、DOM操作)
- Webブラウザが画面を描画する
そこで、次のように(2番目のレンダリングを除くよう)処理を改善しようとした。
- DOM構築
- DOM操作
- レンダリング
例えば、Geckoには、DOM構築が終わったときに発火するDOMContentLoadedイベントが実装されている(WebKitにも実装されているらしい)。
https://developer.mozilla.org/ja/Gecko-Specific_DOM_Events
これはいけると思い、「Prototype & script.aculo.us ―JavaScriptライブラリによるAjaxアプリケーション開発」を読んでいたら、observeメソッドのイベント名として dom:loaded が使えることを知った。だが、IE6やIE7では、DOMContentLoadedイベントが実装されていないようだ。IEの場合に dom:loaded を用いた場合にどうなるかと調べたところ、script要素のdefer属性により、JavaScriptの遅延評価を行っている(だけの)ようだ。
script要素のdefer属性を用いると、他のscript要素が全て評価された後に、defer属性があるscript要素が評価される。例えば次のようなHTMLドキュメントであれば、a.js、c.js、b.jsの順に評価される。
<script src="a.js"></script> <script defer src="b.js"></script> <script src="c.js"></script>
しかし dom:loaded を用いても、状況は変わらなかった(やはり二度描画された)。IEでは、b.jsが実行される前に、レンダリングされるということだ。
もうだめかと思ったのだが、、次を見つけた。
http://javascript.nwbox.com/IEContentLoaded/
これには驚いた。早速試したところ、DOM構築、DOM操作、レンダリングの順で処理が実施され(レンダリングは一度だけ)、目的が達成できた。
なお、これらの話題について、以下が参考になった。
http://hisasann.com/housetect/2008/11/prototypejsdomloadedie.html