async属性でレンダリングをブロックするJavaScriptを除去

Googleの「PageSpeedInsights」で、自サイトのページをチェックすると、修正が必要な事項のひとつとして、「スクロールせずに見えるコンテンツのレンダリングをブロックしているJavaScript/CSS を排除する」というものがありました。

修正方法を表示させてみると、問題となるJavaScriptの外部ファイルとcssの外部ファイルの一覧とともに、以下のようなメッセージがありました。

このページには、レンダリングをブロックするスクリプトリソースが○個、CSSリソースが○個あります。これが原因で、ページのレンダリングに遅延が発生しています。
以下のリソースによる読み込みが終わるまで、このページでスクロールせずに見えるコンテンツを何もレンダリングできませんでした。ブロックするリソースの読み込みを遅延させるか、非同期に読み込むか、これらのリソースの重要部分を HTML 内に直接インライン化してください。

要するに、ブラウザがレンダリングを行う際に、問題の外部ファイルを読み込む間、レンダリングが途中で中断され、遅延が発生しているので、問題のファイルの読み込みなどを遅らせるなどの対処を行い、レンダリングが遅延なく行われるようにする必要があるということのようです。

レンダリングとは、そのページのファイルに記述されているHTML、CSS、JavaScriptなどのデータをブラウザが解析を行い、一般の閲覧者にサイトとして表示させる作業のことです。

このレンダリングの解析に時間がかかると、ページの表示スピードが遅いという印象を閲覧者に与えてしまいます。

さっそく、問題のcssファイルとJavaScriptファイルの改善を行うことにしました。

CSSの配信を最適化する

Googleのヘルプ、「CSSの配信を最適化する」を見てみますと、cssの容量が比較的小さい場合は、サイトが一番最初に表示されるファーストビューの表示に必要な最低限のcssを抜き出して、インライン化する方法が提案されています。

つまり、そのページのスクロールせずに見れる部分に必要なcssをhtmlに直接記述するということのようです。

しかし、自サイトのcssファイルはそれほど小さいものではなく、またファーストビューに必要な箇所を抜き出すのも本来はそこまですべきでしょうが面倒だったので、この方法は保留にしました。

その代りに、自サイトでは2つの外部cssファイルを読み込ませていたものを、なんとか一つにまとめ、一つのcssファイルを読み込ませるようにしたところ、「PageSpeedInsights」で再分析を行った結果、cssの指摘箇所はクリアしました。

複数のcssファイルをできるだけまとめるだけでも効果があるようです。

レンダリングを妨げるJavaScriptを削除する

同じくGoogleのヘルプ、「レンダリングを妨げるJavaScriptを削除する」を見てみますと、JavaScriptの解決策として、まず一つ目に、ファーストビューの表示のために小さなJavaScriptをインライン化することが提案されています。

これも自サイトでは難しいようなのでパス。

もう一つのJavaScriptの読み込みを遅らせる解決策をとりました。

読み込みを遅らせるには、HTML内の<script>タグに、「async属性」を記述することが提案されています。

async属性とは、ページの解析を続けながら、スクリプトを非同期にダウンロードし、スクリプトは、ダウンロードの完了後に実行させるもので、レンダリングを妨げないというものです。

async属性はHTML5から新たに加わった属性で、HTMLの<script>タグに以下のように記述します。

<script async src=”example.js”></script>

なお、async属性は<script>タグにsrc属性が指定されている場合にのみ使用することができます。

async属性をPageSpeedInsightsで指摘されている<script>タグすべてに記述し、再度、PageSpeedInsightsで再分析を行いました。

すると、パソコンでは4ポイント、モバイルでは9ポイント改善されました。

しかし、肝心のJavaScriptで動作するコンテンツがうまく動かないという事態になってしまいました。

動作しないスクリプトは以下のようになっていて、「b.js」は「a.js」に依存しています。

<script async src=”a.js”></script>
<script async src=”b.js”></script>

非同期に読み込む際には、依存関係にある複数のスクリプトの順序についてGoogleヘルプにも注意が促されていますが、読み込み順序は適切だと思っていました。

しかし、いろいろ調べてみますと、async属性を記述したすべてのスクリプトの内、比較的小さなファイルから読み込まれるようなのです。

つまり、上記の例ですと、「a.js」と「b.js」の間に、他のさらに小さなファイルが挟まって読み込まれ、それによって動作しないのではないかと考えました。

ファイルサイズを測って、順序を入れ替えようとも思ったのですが、それよりも、「a.js」と「b.js」をひとつにまとめた方が早いと思い、一つにまとめ、そのファイルにasync属性を記述して試したところ、無事動作しました。

async属性を使って非同期で読み込ませる際には、このように各スクリプトの容量や順序に気を付ける必要がありそうです。

async属性の各ブラウザ対応状況

async属性は、上述しましたようにHTML5からの仕様なので、まだ対応していないブラウザがあるとのこと。

対応状況はコチラで確認できます。

この対応状況を見てみますと、現時点ではIE8、IE9、OperaMini、AndroidBrowzer2.3などでまだ未対応のようです。

なので、未対応のブラウザに対しても対応させたい場合は、async属性と併せてdefer属性も記述しておいた方がいいかと考えました。

defer属性は、ページの解析が終了した後にスクリプトを実行させるものです。

以下のように記述しました。

<script async defer src=”example.js”></script>

これで、asyncをサポートするブラウザーではasync属性を使い、asyncをサポートしないブラウザーではdefer属性を使用するようになります。

未対応ブラウザーでの動作は確認していませんが、たぶんこれでうまくいくはずかと思います。

なお、「async defer」を両方記述しても、PageSpeedInsightsの分析上は変わりありませんでした。