メインコンテンツへ移動

インラインスクリプトの配置

無料2015-11-27#JS#Solution#JavaScript行内脚本#css阻塞渲染#逐步渲染

インラインスクリプトの配置場所が不適切だと、CSSもページのレンダリングをブロックする可能性があります。

1. インラインスクリプトによるレンダリングブロックを避ける

  • インラインスクリプトを最下部(body 終了タグの直前)に移動する

  • 非同期コールバックを使用して JavaScript の実行を開始する

  • script タグの defer 属性を使用する

インラインスクリプトを最下部に移動する

インラインスクリプトを body の終了タグの直前に配置します。

メリット:シンプルで使いやすく、ページ内の画像などのリソースと最下部のインラインスクリプトが並列にダウンロードされます。

デメリット:依然としてページのレンダリングをブロックします。インラインスクリプトの実行時間が長い(300ms以上)場合は、この単純な方法は避けるべきです。

非同期でスクリプトの実行を開始する

setTimeout(doStuff, 0) を使用してスクリプトを非同期に実行します。Firefox では 250ms の遅延が必要です(250は Nglayout.initialpaint.delay に基づきます)。

メリット:段階的レンダリング(プログレッシブレンダリング)を実現できます。インラインスクリプトの実行が始まる前に、ブラウザは先に DOM コンテンツ(多くはテキスト)をレンダリングします。

デメリット:画像のレンダリングをブロックします。画像のレスポンスが返ってきたときに doStuff が実行中であれば、画像は doStuff が終了するまで表示されません。その場合は setTimeout を諦め、window.onload を使ってスクリプトの実行を開始すべきです。もちろん、インラインスクリプトの実行時間が非常に短い(300ms未満)場合は、setTimeout を使っても問題ありません。

P.S. 実行時間の非常に長いインラインスクリプトに対する理想的な解決策は、300ms ごとに分割して実行すること(setTimeout(doChunk, 300))ですが、大きなロジックを小さな断片(300ms以内に完了するもの)に分割するために大規模なコードのリファクタリングが必要になります。

script タグの defer 属性を使用する

defer 属性はインラインスクリプトにも適用可能であり、ブラウザがページの解析とレンダリングを続けながら、インラインスクリプトの実行を遅らせることを許可します。

メリット:リソースの並列ダウンロードが可能です。

デメリット:レンダリングをブロックします。実行時間の短いインラインスクリプトにのみ適しており、非常に長いスクリプトには依然として setTimeout が必要です。

2. スタイルシートもインラインスクリプトをブロックする

JavaScript が読み込み順に実行されるだけでなく、ブラウザはCSS も読み込み順に解析されることを保証します(解析順序が異なると、スタイルの優先順位による上書きルールなど、最終的なスタイルの結果が変わる可能性があるためです)。

あまり知られていないこと:ブラウザは CSS と JS の解析順序も維持します。インラインスクリプトをスタイルシートの後に配置すると、リソースのダウンロードが著しく遅延します(結果として、スタイルシートのダウンロードが完了し、かつインラインスクリプトの実行が終わるまで、後続のリソースのダウンロードが開始されません)。

これは、インラインスクリプトの中に、スタイルシート内のスタイルに依存するコード(例:document.getElementsByClassName())が含まれている可能性があるためです。

結論:スタイルシートの後に配置されたインラインスクリプトは、すべての後続リソースのダウンロードをブロックします(言い換えれば、スタイルシートの後にインラインスクリプトがなければ、スタイルシートは他のリソースと並列にダウンロードされます。もちろん、インラインスクリプトの前にスタイルシートがあるかどうかにかかわらず、インラインスクリプト自体は常に後続リソースのダウンロードをブロックします)。

3. まとめ

インラインスクリプトは CSS をブロッキングなものに変えてしまう可能性があります。外部スクリプトのみを引用するようにすれば、この問題を回避できます。

参考資料

  • 『続・ハイパフォーマンスWebサイト ― ウェブ高速化のベストプラクティス』

コメント

コメントはまだありません

コメントを書く