JavaScript の document.write で動的に書き出した scriptタグ 内の JavaScript の実行順序を調べました。

以下の通りマークアップ+コーディングしたとき、アルファベット a~k がどのように出力されるか実験しました。
検証コード
HTML
<!doctype html>
<html>
<head></head>
<body>
a
<script>
document.write('<scr' + 'ipt>document.write("b");<\/scr' + 'ipt>');
document.write('c');
</script>
d
<script>
document.write('<scr' + 'ipt>var E = "e";<\/scr' + 'ipt>');
document.write(E);
</script>
f
<script>
document.write('<scr' + 'ipt src="g.js"><\/scr' + 'ipt>');
document.write('h');
</script>
i
<script>
document.write('<scr' + 'ipt src="j.js"><\/scr' + 'ipt>');
document.write(J);
</script>
k
</body>
</html>
g.js
document.write('g');
j.js
document.write('<scr' + 'ipt>var J = "j"<\/scr' + 'ipt>');
ソース コードだけで正確に予測できる人は いないと思う。尚、Chrome(42.0.2311.90)、IE11、FireFox(37.0.1)の各主要ブラウザで表示結果は同じでした。
結果
a bc d e f gh i k
j だけ出力されないという結果。あとはアルファベット順に出力されます。iframe でも貼っておくのでお使いのブラウザでの結果をご確認ください。
iframe
動的に生成された HTML
ページの HTML が最終的にどうなっているか見てみます。これがすべての謎を解く鍵だ。
<!doctype html>
<html><head></head>
<body>
a
<script>
document.write('<scr' + 'ipt>document.write("b");<\/scr' + 'ipt>');
document.write('c');
</script><script>document.write("b");</script>bc
d
<script>
document.write('<scr' + 'ipt>var E = "e";<\/scr' + 'ipt>');
document.write(E);
</script><script>var E = "e";</script>e
f
<script>
document.write('<scr' + 'ipt src="g.js"><\/scr' + 'ipt>');
document.write('h');
</script><script src="g.js"></script>gh
i
<script>
document.write('<scr' + 'ipt src="j.js"><\/scr' + 'ipt>');
document.write(J);
</script><script src="j.js"></script><script>var J = "j"</script>
k
</body></html>
この最終的な HTML の記述順序で JavaScript が実行されたわけではないのが ややこしい。
7~10行目の b~c についていうと、8行目の document.write で 10行目の script タグが書き出され、それがすぐに評価(実行)されたあと、9行目の document.write(‘c’) が実行されるため、結局はアルファベット順通り、bc という出力になります(10行目末尾)。
e も同じ理屈で正しく出力されます。
gh も同じ理屈ですね。外部スクリプトも同期実行なので、ちゃんとアルファベット順になります。
j が問題だ。実験の結果からすると、documento.write で script タグの書き出しをネストした場合、同期実行されるのは入れ子になっている親子まで、という動作。でも孫の var J = “j” はちゃんと実行されていて、例えば k のあとに document.write(J) すると j が出力されます。
すべての主要ブラウザで同じ結果ということは、仕様通りの動作ぽい。でも裏付けを取るのはやめました。筆者には必要ない。どうしても真実を探求したい人は、以下のページがヒントになるかも知れない(筆者注:ならないかも知れない)。
筆者は恥ずかしながら、WHATWG の存在を始めて知りました。Web って色んなものから できているんですね。
ちなみに、document.write するスクリプトは色んな人が「やめろ」いや もとい「お願いだから やめてくれ」と言っています。この闇を振り払えるのは、あなた達のような若いエンジニアだけだ。頼んだぞ!