JS memo

お洒落にJavaScript。

2019年1月22日7:15

Javascriptのasyncとdeferの使い方

メインビジュアル

Javascriptのasyncとdeferの使い方

<script>タグで書かれた外部のjsファイルを非同期に読み込む最も簡単な方法を説明します。JavaScriptが理解できなくてもできる方法です。外部のjsファイルのせいでサイト速度が遅いことが悩みの方はこの方法を試してみてください。

    目次

  1. 外部jsファイルの読み込み方
  2. async
  3. defer
  4. まとめ

外部jsファイルの読み込み方

実際にドキュメント(html)をブラウザに表示させる時に、外部のjsファイルはどのように読み込まれるのでしょうか。
基本的に何も特別な記述をしない限り、ドキュメントを上から順にパース(読み込み)します。そのため、途中でscriptタグが現れると一旦htmlの読み込みを中断して、scriptタグに書かれた内容を読み込みに行きます。これはscriptが外部ファイルでもインラインでも同様です。

以下のjsファイルはh1タグに”JavaScript”を追加してという指示をしたものです。

test.js
function onLoad(){
  const target = document.getElementById("h1");
  target.innerHTML = "JavaScript";
}
onLoad();

上記のjsをhtmlファイルに書きます。

test.html
<!DOCTYPE html>
<html>
<body>
  <h1 id="h1">
  <script type="text/javascript" src="./js/test.js">
</body>
</html>

このhtmlファイルの読み込み過程をsafariの開発ツールにあるタイムラインでみてみましょう。

タイムラインの見方についてはコチラ

一旦ドキュメントのパースを中断させて、jsの読み込みが行われています。このように同期的に読み込むことでサイトの速度に影響を与えてしまうのです。
下の方のコンテンツに何らかの仕様を行うjsの場合、ドキュメントを読み終えてから発火させる方がいいですよね。ではその方法をみて行きましょう。

async属性

async属性とは”asynchronous”(非同期的に)の略で、以下の例のようにscriptタグに追記するだけで、ドキュメントのパースと並行して取得してねと指示してくれます。
そのためドキュメントの読み込みを中断させることなく、jsも取得してくれます。

<script style="text/js" src="test.js" async></script>

では先ほどのhtmlファイルにasyncをつけてもう一度タイムラインを見てみましょう。

最初のレイアウトが構築されるまでドキュメントのパースを中断することなくjsファイルが読み込まれました。
※test.jsのあとに再びレイアウトが再構築されていますが、これはjsによる影響でhtmlファイルを読み込み直さないといけないためです。今回の場合、ページ速度は一度目にレイアウトが構築するまでと考えて良いでしょう。

しかしながら、このasync属性で読み込んだjsの実行するタイミングと他のjsとの順序が保証されていません。
下の例ではjquery.min.jsファイルとjqueryで書かれたtest.jsを読み込んでいますが、上手く表示されません。

test.html
<!DOCTYPE html>
<html>
<body>
  <h1 id="h1"></h1>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js" async></script>
  <script type="text/javascript" src="./js/test.js" async></script>
</body>
</html>
test.js
$(function(){
  $("#h1").html("JavaScript");
});

タイムラインをみてみましょう。

jquery.min.jsがtest.jsよりも後に読み込まれており、記述の順番とは逆になってしまいました。ではどちらのjsファイルも非同期的に読み込むにはどうしたらいいでしょうか。

defer属性

defer属性とはasync属性と基本的には同じです。しかしレイアウトを構築した後に「順番を守って実行してね!」と指示することができます。そのため、前述のように順番通りに実行したい場合はdefer属性を用います。

test.html
<!DOCTYPE html>
<html>
<body>
  <h1 id="h1">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js" defer></script>
  <script type="text/javascript" src="./js/test.js" defer></script>
</body>
</html>

タイムラインをみてみましょう

順番通りに読み込まれていますね!

まとめ

それぞれのjsファイルの用途と関係性、asyncとdeferの内容さえ理解していれば、jsが分からなくても大丈夫です。速度改善したいけど、jsを書き変えたくない!って方はまずこの方法を試してみてください