【翻訳】document.writeでSCRIPTを書き出すなやで!

Don’t docwrite scripts

Steve Souders Original:Don’t docwrite scripts)by Steve Souders

昨日のブログ記事のHTTP Archiveが速くなっている、大きな要因の一つとしてはスクリプトローダーを使用しないことです。そのスクリプトローダーとはスクリプトを動的に読み込むためにdocument.writeを使用しているものです。振り返れば、私は2009年4月のブロッキングなしのスクリプト読み込み続・ハイパフォーマンスWebサイト(4章)において、document.writeテクニックについて記述していました。それは以下のようなものです。

document.write('<script src="' + src + '" type="text/javascript"><\/script>);

document.writeを使ったスクリプトローダーの問題点:

  • 挿入したスクリプトより下の全てのDOM要素はスクリプトのダウンロードが完了するまでレンダリングがブロックされます。 (example).
  • また、ほかの動的読み込みもブロックします (example)。例外としては、複数のスクリプトが同一のSCRIPTブロック内にdocument.writeを使用して注入された場合です(example)。

document.writeを使用したスクリプトローダーのため、私が最適化しようとしたページのレンダリングは遅れ、同じページ内の他の非同期スクリプトに関しても読み込みに時間がかかるようになりました。私はこのスクリプトローダーをはずし、非同期にスクリプトを読み込むために代わりのコードを書きました。それはGoogle アナリティクスの非同期スニペットで有名になった createElement-insertBefore パターンです。

var sNew = document.createElement("script");
sNew.async = true;
sNew.src = "http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js";
var s0 = document.getElementsByTagName('script')[0];
s0.parentNode.insertBefore(sNew, s0);

なぜdocument.writeによる非同期読み込みはこのような悪いパフォーマンスになってしまうのでしょうか?

順を追って考えて見れば、そんなに不思議なことではありません。通常のマークアップによるSCRPT SRC=読み込みは後続のDOM要素のレンダリングを止めることを既に私たち知っています。また、スクリプト実行段階を抜ける前にdocument.writeは評価され、その後、ページのパースが再開されることも理解しています。したがって、通常のSCRPT SRC=をスニペットとした document.writeテクニックは残りのページのレンダリングをブロックしてしまいます。

反対に、createElement-insertBeforeテクニックはレンダリングをブロックしません。事実、document.writeでcreateElement-insertBefore スニペットを生成しても、そのときレンダリングはブロックされません。

ブロッキングなしのスクリプト読み込み記事での私の結論はスクリプトロード手法を選択するための決定木を使用することです。そうすれば異なるシナリオにおいてどの非同期読み込みテクニックを選択するか困らないでしょう。また注意深く見れば、document.writeの使用は決して推奨されないこともお分かりになるでしょう。Webの世界はたいへん多くのものが移り変わりますが、私が2009年に出したアドバイスは今日においても正しいのです。


改めて、続・ハイパフォーマンスWebサイトを読んでみるとdocument.writeテクニックはIEのときだけ並列ダウンロードされますと書いてある。しかもスクリプトのダウンロード中は他のリソースはブロックされるとも書いてあり、そもそも使う用途が限定的だなと印象。