27 March 2010

script要素で外部jsをロードする際のレンダリング遅延

script要素による外部jsのロード

たとえば簡単なブログパーツなどをサイトに貼り込む際にscript要素で外部jsを読み込む場合があります.

<script type="text/javascript" src="http://www.example.com/foo.js">script>

この例のfoo.jsは, 動的にhtmlを生成しdocument.write()メソッドでそれを書き出す, という風に動作すると考えてください. このように別ドメインのリソースをjs経由で自サイトに表示させるというパターンは, 例えばサイト内広告などでわりと一般的だと思います.

こうした場合, ページのレンダリングに遅延がおこりえます. script要素で挿入されるjsスクリプトはページの内容を書き換える(追記する)可能性があります. よってブラウザはhtmlの解釈中に, script要素に達した時点でいったんレンダリングを止め, jsのダウンロードと解釈を行い, それが完了した時点でのこりのhtmlのレンダリングを再開します.

<p>pre scriptp>
<script type="text/javascript" src="http://www.example.com/foo.js">script>
<p>post scriptp>

このようなhtmlの場合, ブラウザは"pre script"というパラグラフを表示させたあと, foo.jsをダウンロードし実行, そのあとに"post script"を表示します.

このようにscript要素は同期通信っぽくなっています. 前にも述べたようにjsスクリプトが新しいhtmlを追加したりする可能性があるので, ブラウザのこの動作は理にかなったものだといえます. いっぽうimgやiframe要素は, 外部の画像やhtmlの読み込みと同時に以降のhtmlのレンダリングを行うという, 非同期通信っぽい動作をします.

レンダリングの遅延

scriptタグで指定されたスクリプトのダウンロードと実行がおわらないと, そのあとの要素のレンダリングが行われません. そのため, もしスクリプトのダウンロードに時間がかかったり, 実行時間が長くなってしまったりすると, ページの表示が途中で止まってしまうことになります. もし相手先のサーバになにか障害がおこって, タイムアウトするまで応答がなかったりすると, ページ全体の表示に数十秒かかってしまうということも考えられます.

対応策

代替要素を置いてあとで置き換える

先にdivなどで場所をとっておいて, 読み込みが完了し次第jsのdom操作で置き換えるという方法です. サーバ側・クライアント側の両方に手を加える必要があるのでいつでもできるわけではありませんが, 確実な方法なんじゃないでしょうか.

最速インターフェース研究会 :: ページレンダリングを妨げない広告挿入手法に関する覚書

script要素をページ後方におく

原始的ですがこうすることで影響を最小限におさえられます.

defer属性

本題とはずれますがdefer属性というものがあります. これはscript要素に追加できる属性で, "この外部スクリプトはページの内容を書き換えません"ということをブラウザに伝える働きをします. deferが指定されたscript要素の外部スクリプトは, ページのレンダリングが終わったあとに実行されるようになります. ページの内容を書き換えないスクリプトだけが対象なので, スクリプト内にdocument.write()などがあってはいけません.

<p>pre scriptp>
<script type="text/javascript" src="http://www.example.com/foo.js"; defer="defer">script>
<p>post scriptp>
// foo.js
documnt.write("rewrited");

例えばこのように, foo.jsを読み込むhtmlがあり, foo.jsは"rewrited"という文字を書き出すものとします. はじめブラウザは2つのパラグラフを描画し, そのあとfoo.jsを実行します. そのため最終的には内容が"rewrited"という文字だけになってしまいます.

より詳しくは, 以下のhacks.mozilla.orgの記事がわかりやすかったです.

the script defer attribute ★ Mozilla Hacks – the Web developer blog

さらに調べるには

上記の内容は軽く調べてすこし考えただけなので, もっと良いアイデアがある可能性があります. 実際に世で使われているscriptを調べたり, あるいは本で勉強するのが良いと思います. 読んだことはないんですが, 書名的にハイパフォーマンスwebサイトでこうした内容を扱っているかもしれません. 目次を見たところ6章の"ルール6:スクリプトは最後に置く"が関連していそうなので, 機会があれば読んでみたいです.

参考