ノラWEB屋 野良人(のらんど)- 個人営業のWEB屋さん

defer属性で読み込んだjQueryプラグインの関数をインラインで呼び出す際の注意点

2017年12月6日

表示速度の高速化のためにdefer属性を利用する際の注意点かなにかのメモ書き。

    レンダリングを高速化させるためにscript要素にdefer属性を設定

    GoogleのPageSpeed Insightsとかで確認すると、「レンダリングをブロックする JavaScript を除去してください」とか怒られる場合があります。

    これはjsファイルを読み込むと、そのファイルの実行が完了するまでHTMLのレンダリングがブロックされてしまうのでページの読み込みに時間がかかっているぞ、というお叱りです。

    よくある改善策としてはscript要素にdefer属性を設定することで、jsファイルの実行をHTMLパース完了後にするというものです。こういうやつです↓↓

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js" defer></script>
    <script src="jQuery/myScript.min.js" defer></script>
    

    参考記事です。図が分かりやすい。

    <script> タグに async / defer を付けた場合のタイミング – Qiita

    現象:jqueryファイルを読み込むscript要素にdefer属性を付けていたらプラグインの関数が実行されない

    さて、jQuery関数をプラグイン化して必要に応じて呼び出してもらう、みたいなものを作ってdeferっていたらハマりました。

    状況としてはこのような感じです。

    <head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js" defer></script>
    <script src="jQuery/myPlugin.min.js" defer></script>
    </head>
    <body>
    <script>
    $(function() {  $('body').myFunction(); });
    </script>
    </body>
    

    こうすると呼び出したmyFunction()関数はエラーが出て実行されません。

    原因:インラインのscriptはHTMLパース中(依存関係にあるjsファイルの実行前)に実行される

    というわけで、インラインで関数を呼び出しても、プラグイン本体や、そもそもjQuery本体も実行前なので機能しません。

    <script defer>
    $(function() {  $('body').myFunction(); });
    </script>
    

    ↑とかしてもだめです。

    対応:onloadイベントで呼び出す

    <script>
    window.onload = function(){
    	$(function() {  $('body').myFunction(); });
    }
    </script>
    

    または

    <script>
    window.addEventListener( 'load', function(){
    	$(function() {  $('body').myFunction(); });
    }, false);
    </script>
    

    まーどっちにしても、DOM操作をする場合だと一旦パースしてからの適用になるため表示がカクってなったりもするので、高速化を諦めるか、プラグインを使わないやり方に切り替えたほうが良い気はしますです。

    ▼参考

    scriptのdefer/asyncを理解し、ページの高速化方法を探る | ゆっくりと…
    このエントリーをはてなブックマークに追加