WEB/システム/IT技術ブログ

外部JavaScriptを非同期(async / defer)で読み込みレンダリングを高速化する

Googleのサービス「PageSpeed Insights」の解析結果で「修正が必要:スクロールせずに見えるコンテンツのレンダリングをブロックしている JavaScript/CSS を排除する」という項目があります。
レンダリング中にJavaScriptを読み込むことで、画面表示に遅延が生じているという警告のようです。
(CSSについては別途考えます)

そこで、HTML5から追加された属性「async」と「defer」を使って、スクリプトの読み込みを非同期にし、画面表示の高速化を図ってみたいと思います。

概要

HTMLのソースは上から順に解析されます。
ソース上部に大量のJavaScriptを読み込んだ場合、その読み込みに時間がかかる分だけ画面の表示が遅くなります。

少し前までは、JavaScriptはhead部分ではなく、bodyの閉じタグの直前で読み込むことが奨励されていました。
読み込み順を変更することで、レンダリングへの影響を抑えようということですが、この方法では結局、トータルの読み込み時間としては改善していないんですね。

そこでHTML5から実装された属性「async」と「defer」。これを指定すれば、画面の読み込みとは別で外部のJavaScriptを非同期で読み込むので、レンダリングへの影響がなくなるということです。
但し、スライダーやカルーセルなど、見た目を構築するスクリプトについては、その部分の表示に遅れなどが発生します。

「async」と「defer」の違いは、読み込み順を保持するか否かで、性能にはそれほど差はないといわれています。

asyncを導入

まず、asyncを使った方法です。
以下のようにスクリプトタグに属性「async」を指定するだけです。

<script type='text/javascript' src='/js/jquery.min.js' async></script>
<script type='text/javascript' src='/js/bootstrap.min.js' async></script>
<script type='text/javascript' src='/js/script.js' async></script>

注意しなければならないのは、「asyncは読み込み順を考慮しない」ということです。
つまり、タイミングによって、jqueryを必要とするbootstrapやオリジナルのscriptが先に読み込まれる可能性があります。このケースだと、逆に読み込まれるとスクリプトエラーになってしまいます。

asyncを利用する場合は、それぞれのjsファイルの読み込み順に依存関係がないことが前提となります。

deferを導入

deferを利用する場合は、以下のように指定します。

<script type='text/javascript' src='/js/jquery.min.js' defer></script>
<script type='text/javascript' src='/js/bootstrap.min.js' defer></script>
<script type='text/javascript' src='/js/script.js' defer></script>

asyncに対して、deferは読み込み順を維持します。
このケースだとjquery、bootstrap、scriptの順で読み込むのでスクリプトエラーの心配はなく、レンダリングの速度向上が期待できます。

APIスクリプトも非同期でも読み込む

Facebook、InstagramやTwitterなどのAPIをページに導入する際、通常JavaScriptで組み込みますが、各々でasyncの設定が可能です。
例えばTwitter widgetの導入は以下のようなコードを設置します。

!function(d,s,id){
	var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';
	if(!d.getElementById(id)){
		js=d.createElement(s);js.id=id;
		js.src=p+"://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);
	}
}(document,"script","twitter-wjs");

これに「js.async=true;」を追記することで、非同期読み込みが設定できます。

!function(d,s,id){
	var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';
	if(!d.getElementById(id)){
		js=d.createElement(s);js.id=id;js.async=true;
		js.src=p+"://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);
	}
}(document,"script","twitter-wjs");

これらAPIスクリプトは、先ほどのjqueryなどローカルスクリプトとは依存関係がないのがほとんどなので、asyncを使用しても問題ないでしょう。

実際に対策した結果

deferを設置した後、「PageSpeed Insights」で解析してみて「修正が必要:スクロールせずに見えるコンテンツのレンダリングをブロックしている JavaScript/CSS を排除する」の項目が改善していれば成功です。

実際に私の運営している4サイトで、この対策を実行してみて、対策前後で「PageSpeed Insights」解析結果のスコアを比較してみました。

  モバイル パソコン
対策前 対策後 対策前 対策後
サイト1 54 / 100 57 / 100 65 / 100 66 / 100
サイト2 70 / 100 69 / 100 79 / 100 77 / 100
サイト3 69 / 100 65 / 100 77 / 100 75 / 100
サイト4 70 / 100 66 / 100 79 / 100 77 / 100

。。。サイト1では微量ながら改善したようですが、他のサイトではスコアが下がってしましました。なぜ。。

ただ「スクロールせずに見えるコンテンツのレンダリングをブロックしている JavaScript/CSS を排除する」のJavaScriptの項目は表示されなくなり、体感的にも少しレンダリングが早くなったように感じるのですが。

引き続き同項目のCSSを対応して、合わせて評価してみたいと思います。

B!

Pingback & Trackback

Comment

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

Monthly Archives