だれかのなにかに役立てるウェブ制作者YoTaの趣味ブログ

js読込場所をbody最後に書く理由は「DOMツリー構築の読込速度向上のため」

先日、webページの速度改善を勉強し、jsの読込場所をbody最後に置いた方が良い理由を学んで、実際に試してみました。

結果画面

こちらが、headタグにjsを置いていた時のNetworkパネルです。

js読込場所の改善前

DOMContentLoadedが847msで発火しています。

そして、bodyタグ最後にjsを置いた時のNetworkパネルです。

js読込場所の改善後

DOMContentLoadedが546msで発火しており、かなり速くなりました。

wordpressでは、wp_enqueue_scriptを用いてjs指定していると、「true/false」のオプション記述で、wp_head()かwp_footer()のどちらかに、カンタンに読込場所を切り替えられて便利です。

説明

DOMContentLoadedは、パースが完了(DOMツリーの構築が完了)した時点で発火されるものです。もう少し詳しく書くと、HTMLドキュメントのロード完了を示し、その他サブリソースのロードは保証しないが、script要素がある時は、スクリプト処理でCSSOMにアクセスする可能性があるため、ブラウザはスクリプト処理を実行する前に、CSSのロード完了を待ちます。

つまり、js読込をheadで宣言すると、サブリソースの絡みもあり、DOMツリー構築が遅くなり、js読込をbody最後に宣言すると、純粋にDOMツリー構築に専念できるので速くなるって感じです。

ケースバイケースの使い分けで良い

jsの記述内容によっては、headで宣言しないと都合悪い場合もあると思うので、そういう時はheadで良いかと思います。

それに、先ほどのキャプチャ結果をみても分かるように、DOMツリー構築が早く完了しても、Load自体にクリティカルな影響を及ぼすケースはそんなにないとは思うので、通常のwebサイトなどであれば、あんまり神経質にならなくても良いのかもしれません。(Loadは、ツリー構築後、画像やスクリプトなどの処理・レンダリングが終わったところを示します。)

また、headで読込させる際は、非同期の記述をする方法もあります。

jsを非同期で読込させる手段も

非同期読込させる時は、asyncとdeferがあります。この二つは似ているようで、明確に違いがあるので、正しく認識しておくことが大事です。

defer属性
・非同期でjsを読込する。(ドキュメントのパースと併行する)
・読込したjsは、ドキュメントのパースが終わり、DOMツリーの構築がされてから初めて実行される

async属性
・deferと似ているが、asyncでは、読み込んだjsの実行タイミングと実行順の保証がない
・async読込のjsは、ドキュメントのパースが終了していない段階から読み込まれて、また、所定の順番で読込&実行されないので、使いどころがムズイ。

DOMツリーの構築がきちんと終わってから、jsのスクリプト処理をさせたい時は、deferを使うことが大事です。

また、注意点として、defer属性かasync属性を使った時は、ドキュメントのパースをブロックしてしまうdocument.writeなどが使えなくなるので、記述内容には注意が必要です。

余談:レンダリングについてはちゃんと勉強したほうが良い

いくつか、jsの設置個所に関する記事を読んでいたのですが、asyncしておけば読込速度改善してオールOK、みたいな乱暴な情報もあったりするので、web速度改善については、きちんと本だったり、詳しく書いてあるサイトで腰を据えて勉強したほうが良さそうです。

ページ上部に戻る