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 するスクリプトは色んな人が「やめろ」いや もとい「お願いだから やめてくれ」と言っています。この闇を振り払えるのは、あなた達のような若いエンジニアだけだ。頼んだぞ!