プロが教える店舗&オフィスのセキュリティ対策術

標準準拠モードと後方互換モードのJavaScriptのパフォーマンスについて

ブラウザはWindows IE8限定とします。
HTMLファイルのDOCTYPE宣言によって標準準拠/後方互換モードを切り替えられますが、
下記JavaScriptをそれぞれで走らせた場合、明らかに標準準拠モードが遅いです。
この差の原因は何なのでしょうか。
後方互換モード程度にまで速度を改善することはできないのでしょうか。

for (var i = 0; i < 10000; i++)
{
var t = document.createTextNode(i + ", ");
var o = document.createElement("div").appendChild(t);
document.getElementById("test").appendChild(o);
}

A 回答 (6件)

#2,3,4,5 です。



改めて考えたら、JavaScriptによるDOM操作時間で比較していたので、window.onload で比較検証してみました。
(全角空白は半角空白に置換してください)

---------
<!DOCTYPE html>
<html lang="ja">
<head>
 <meta charset="utf-8" />
 <title>test2</title>
<script type="text/javascript"><!--
(function () {
 var start = new Date();

 function init (event) {
  var doc = this.document,
    time = (new Date().getTime() - start.getTime()) / 1000;
  doc.getElementById('Time').appendChild(doc.createTextNode(time + ' seconds'));
 }

 attachEvent ('onload', function (event) { init.call(this, event); });
}) ();
//--></script>
</head>
<body>

<p id="Time"></p>

<table id="Test">
 <tbody>
  <tr><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td><td>10</td><td>11</td><td>12</td><td>13</td><td>14</td><td>15</td><td>16</td><td>17</td><td>18</td><td>19</td><td>20</td><td>21</td><td>22</td><td>23</td><td>24</td><td>25</td><td>26</td><td>27</td><td>28</td><td>29</td><td>30</td></tr>
 </tbody>
</table>

<script type="text/javascript"><!--
(function () {
 var doc  = document,
   df  = doc.createDocumentFragment (),
   tbody = doc.getElementById('Test').tBodies.item(0),
   tr  = tbody.rows.item(0),
   i;

 for (i = 0; i < 1000; i++) { df.appendChild(tr.cloneNode(true)); }
 tbody.appendChild (df);
}) ();
//--></script>

</body>
</html>
---------

// --- DOCTYPE有り
4.703
4.484
4.625
4.407
4.375
平均: 4.5188 (sec)

// --- DOCTYPEなし
2.109
2.703
2.938
2.5
2.453
平均: 2.5406 (sec)


「平均 1.9782秒 後方互換モードが高速」という結果になりました。

<style>table { table-layout: fixed; } td { width: 2em; } </style>

を入れても、あまり変わらないようです。

> 後方互換モード程度にまで速度を改善することはできないのでしょうか。
table要素は最後まで読み込まれなければ描画できず、描画に関わる計算量も多いので、あまりに長い記述だと描画速度は著しく低下します。
特に、IEは描画速度が遅いですから尚更に…。(GoogleChrome5 なら標準準拠モードでも 1秒 で描画完了します)

・tableを出来るだけ使わない
・1ページにあまり多くを詰め込みすぎない

が最善だと思いますが、どうしても1ページに詰め込みたいのなら遅延読み込みを利用して負荷を下げる工夫があるといいと思います。
例えば、JSONにデータを格納して、Autopagerize的なスクリプトを組むとか、検索フォームから検索できるようにするとか。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
やはりこれ以上の描画高速化を狙うなら、描画要素数自体を減らすしか無さそうですね。
実際のページも、後方互換モードなら問題の無い速度なのですが・・・
何度もご丁寧にありがとうございました。

お礼日時:2010/07/04 09:28

#2,3,4 です。



> 検証に使用したコードですが、tableの方は以下のものです。
さすがに1000行にわたるHTMLをそのまま記載するわけにはいかなかったので、JavaScriptで生成してみました。
(全角空白は半角空白に置換してください)

--------------
<!DOCTYPE html>
<html lang="ja">
<head>
 <meta charset="utf-8" />
 <title>test2</title>
</head>
<body>

<p id="Time"></p>

<table id="Test">
 <tbody>
  <tr><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td><td>10</td><td>11</td><td>12</td><td>13</td><td>14</td><td>15</td><td>16</td><td>17</td><td>18</td><td>19</td><td>20</td><td>21</td><td>22</td><td>23</td><td>24</td><td>25</td><td>26</td><td>27</td><td>28</td><td>29</td><td>30</td></tr>
 </tbody>
</table>

<script type="text/javascript"><!--
(function () {
 var doc  = document,
   df  = doc.createDocumentFragment (),
   tbody = doc.getElementById('Test').tBodies.item(0),
   tr  = tbody.rows.item(0),
   start = new Date(),
   time, i;

 for (i = 0; i < 1000; i++) { df.appendChild(tr.cloneNode(true)); }
 tbody.appendChild (df);

 time = (new Date().getTime() - start.getTime()) / 1000;
 doc.getElementById('Time').appendChild(doc.createTextNode(time + ' seconds'));
}) ();
//--></script>

</body>
</html>
--------------

DOCTYPE宣言の有無でスイッチを入れ替えて検証しました。

// --- DOCTYPE有り
0.625
0.656
0.657
0.656
0.64
平均: 0.6468 (sec)

// --- DOCTYPEなし
0.969
1.313
1.235
0.906
1.141
平均: 1.1128 (sec)

「平均 0.466秒 標準準拠モードが高速」という結果になりました。

> tableの代わりに<span>a</span>を数万並べただけのものです。
1000行ならまだわかりますが、数万はさすがに大すぎじゃないでしょうか。

> できれば標準準拠にしたいのですが・・・
何となく、DOCTYPEスイッチではない部分に原因があるような気がします。
#4 でも触れましたが、書き方一つで描画速度はかなり変わります。
「HTML-lint」「The W3C Markup Validation Service」でHTMLが正しい記述かどうか確認してみたり、HTMLはシンプルにしてCSSで可能な限りレイアウト、デザインを指定する、だけでも大分変わるのではないかと想像します。

Another HTML-lint gateway
http://openlab.ring.gr.jp/k16/htmllint/htmllint. …
The W3C Markup Validation Service
http://validator.w3.org/
    • good
    • 0

#2,3 です。



> 例えば膨大な要素数のHTMLファイル(大きなtableだったり、spanタグを数万個並べたり)でも、
実際のHTML,CSSを見てみないと確かなことはいえませんが、そこまで極端なHTMLで検証するっていうことは、元のHTMLも同じような状況なのでしょうか?
書き方に問題があるのかもしれませんね。

Webサイトの高速化 フロントエンドのパフォーマンスの重要性 (Yahoo! developer netoworkより翻訳) | 株式会社インターオフィス
http://www.inter-office.co.jp/contents/177/
Web ページを高速化する
http://www.ibm.com/developerworks/jp/web/library …
表示のスピードアップ
http://kasayan86.hp.infoseek.co.jp/hp/speedup.htm
17.5.2 表幅アルゴリズム ('table-layout'特性)
http://www.y-adagio.com/public/standards/tr_css2 …
table要素のレンダリングの速度 - クライアント・サイド・スクリプティング with Web Standards
http://d.hatena.ne.jp/vwxyz/20081030/1225361077

> この現象が私の環境限定なのか、一般にそうなのかが分かりません。
再現条件を特定するか、全コードを記載(あるいは、URLを開示)しないことには、私も検証できませんので…。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
検証に使用したコードですが、tableの方は以下のものです。

<html>
<body>
<table>
<tr><td>0</td><td>1</td> ... <td>30</td></tr>
<!-- ↑これを1000行とか -->
</table>
</body>
</html>

1行目にはDOCTYPE宣言を入れます。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN">
ここで、前者の方をいれた方が表示が速い、という結果でした。
<span>タグの検証も、tableの代わりに<span>a</span>を数万並べただけのものです。
こちらの方が差は顕著でした。

こうなると両レンダリングモードのパフォーマンスに差がある、としか思えないのですが・・・
IE8は3つのモードがあるようですが、正確にはIE8モードに限って遅い、という結果です。


今回の質問は、大きな表を操作するDHTMLページの作成において、
DOCTYPEスイッチを後方互換にした方が遥かにパフォーマンスが向上した、というのが発端です。
DOCTYPE宣言の変更についてググッてみても、「○○というコードが動かない」という情報は大量に見つかるのですが、
「パフォーマンスが落ちた」という情報がちっとも見つからず・・・
できれば標準準拠にしたいのですが・・・

お礼日時:2010/07/03 19:47

#2 です。



投稿後、#1さんの回答を見ました。確かにそうですね。
テキストノードを1万回生成するより、1万回の繰り返し処理でテキスト型の変数を生成して、最後にノードを挿入する方が速いです。

<script type="text/javascript"><!--
(function () {
 var doc = document,
   str = '',
   i;

 for (i = 0; i < 10000; i++) { str += i + ', '; }
 doc.getElementById('test').appendChild(doc.createTextNode(str));
}) ();
//--></script>


ただ、innerHTMLは低速です…。

--------
すでに多くの人が、element.innerHTML を使用すると遅くて仕方がないということを知っています。どれぐらい遅いかを調べるために、私は innerText の代わりに innerHTML を使用して "Text" をセルに挿入するテスト ページを作成しました。パフォーマンスは文字どおり、がた落ちでした。合計時間は 3375 ミリ秒になり、前回のテストより 80 パーセントも遅くなりました。このたった 1 つの変更で、最初のバージョンより -5 パーセントに逆戻りしてしまいました。明らかに、innerHTML はかなり低速です。
http://msdn.microsoft.com/ja-jp/library/bb263997 …
--------

## …とここまで書いたところで、#2の補足を読みました。

> このコードはただのベンチマークですので、この処理自体の速度改善は望みません。
原因を探りたいのですよね?
検証なくして、原因を知ることは難しいと思うのですが…。

> レンダリングモードの違いによるパフォーマンスの変化というのは、「あったらおかしい」現象なのでしょうか。
にわかには信じがたいですが、絶対にないとも言い切れません。
ですので、検証が必要だと思い、いろいろなコードを書いています。

率直にいって、質問者さんの環境を再現できるほどの情報が揃っていないので、いろいろと環境を推測しないと私の環境で再現できないと思います。
HTMLなどを省略せず、現象を再現できる全ての記述を開示されれば、検証できると思うのですが…。

この回答への補足

申し訳ありません、下記のお礼の言葉が不足しているので、一応補足します。
下記にある実験は、JavaScriptを使わない純粋なHTMLファイルでの実験です。
明らかな速度差とは、画面の表示が完了するまでの時間です。

補足日時:2010/07/02 15:32
    • good
    • 0
この回答へのお礼

回答ありがとうございます。

私の方でも実験をしてみたのですが、
例えば膨大な要素数のHTMLファイル(大きなtableだったり、spanタグを数万個並べたり)でも、
レンダリングモードの違いで明らかな速度差が出ました。
後方互換モードの方が速いです。

こうなると質問の表題自体が間違ってますね・・・
JavaScriptのパフォーマンスの問題ではないようです。

ただ現在、他の環境を用意できない状態ですので、
この現象が私の環境限定なのか、一般にそうなのかが分かりません。

お礼日時:2010/07/02 15:29

DOCTYPE宣言の有無でIE8にて検証しましたが、有意な差は確認できませんでした。



-----------
<!DOCTYPE html>
<html lang="ja">
<head>
<title>test</title>
</head>
<body>

<div id="test"></div>

<script type="text/javascript"><!--
for (var i = 0; i < 10000; i++)
{
var t = document.createTextNode(i + ", ");
var o = document.createElement("div").appendChild(t);
document.getElementById("test").appendChild(o);
}
//--></script>

</body>
</html>
-----------

> 下記JavaScriptをそれぞれで走らせた場合、明らかに標準準拠モードが遅いです。
標準準拠モード 云々はともかく、遅い理由は appendChild() を10000回起こしていることにあるんじゃないでしょうか。

-----------
var doc = document,
  test = doc.getElementById('test'),
  df  = doc.createDocumentFragment(),
  i;

for (i = 0; i < 10000; i++) { df.appendChild (doc.createTextNode(i + ', ')); }
test.appendChild(df);
-----------

Script雑感: Javascript:appendChild のタイミングで処理速度が変わる
http://zombiebook.seesaa.net/article/33247314.html
DocumentFragmentの考察 - Personnel
http://members.jcom.home.ne.jp/jintrick/Personal …

> var o = document.createElement("div").appendChild(t);
返り値がテキストノードなので、createElementが無駄な処理になってしまっていますね。

Node.appendChild - MDC
https://developer.mozilla.org/ja/DOM/element.app …
    • good
    • 0
この回答へのお礼

回答ありがとうございます。

言葉が足りず申し訳ありません。
このコードはただのベンチマークですので、この処理自体の速度改善は望みません。

レンダリングモードの違いによるパフォーマンスの変化というのは、
「あったらおかしい」現象なのでしょうか。
私の環境では顕著な差が出ているのですが・・・

お礼日時:2010/07/02 14:50

ご提示のコードは単なるベンチマーク用でしょうか、


そうでなく、本当にテキストノードの多量追加がしたいなら、DOMじゃなく
文字列としてまず作ってしまって、最後にinnerHTMLで
ごそっと書き換えてしまった方が早いと思います。
var t ="";
for (var i = 0; i < 10000; i++)
{t+="<div>"+i+", "+</div>";}
document.getElementById("test").innerHTML=t;
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!