0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

defer と asyncとスクリプトの記述位置のアレコレ

0
Last updated at Posted at 2026-03-29

はじめに

JavaScriptの興味ネタの続きになります。

JavaScriptを利用する時に「スクリプト」をどこに書くのか?
他のJavaScriptとの順番は?「defer?」、「async?」ナニコレ?つけるの?つけないの?

を迷うことがあったので、改めて整理しようかと思います。

<script src="fileA.js"></script>

参考サイト

迷いポイントその1

「defer?」、「async?」付ける必要があるの?

その前に、付けていないとどういう動きになる?

image.png

ブラウザは、サーバよりHTMLを受領すると上から順に解析していく。

その過程で「スクリプト」を発見すると、ダウンロード・解析・実行する。
※ MDNの「メモ」の「読み込み」をダウンロード・解析と推測。

気を付けることが「スクリプト」で、HTMLを操作する処理があると、HTMLの解析がまだ終わっていないからエラーになる。

【サンプル】スクリプトで、HTML(ボタン)の表示名を更新

<!DOCTYPE html>
<html>
<head>
  <script>
    // ❌ この時点ではまだ <body> 内の要素は解析されていない
    const btn = document.getElementById('myButton');
    btn.textContent = '更新!'; // btnがnullなのでエラー(TypeError)
  </script>
</head>
<body>
  <button id="myButton">ボタン</button>
</body>
</html>

image.png

スクリプトを書く位置をボタンの後にすると、解消される。

<!DOCTYPE html>
<html>

<head>
</head>

<body>
    <button id="myButton">ボタン</button>

    <script>
        const btn = document.getElementById('myButton');
        btn.textContent = '更新!'; // 正常に動作する
    </script>
</body>

</html>

上から順に解析していく中で、スクリプトを発見し、解析・実行!しても、ボタンを読み込んでいないからエラーになる。

で、スクリプトをボタンの後にすると、動く納得。

とはいえ、書く位置に依存しているとバグりやすいので、他の対処法として「defer」・「DOMContentLoaded」もあるとのこと。(From Gemini)

deferとは?

image.png

defer属性を付与すると、実行が「DOMContentLoaded」イベント発生前になるとのこと。

DOMContentLoaded とは?

image.png

「HTMLの文書」が解析されてから発生するイベント。

先ほどの例だと、ボタンも読み込まれてからかな。

<!DOCTYPE html>
<html>

<head>
    <script>
        document.addEventListener('DOMContentLoaded', () => {
            const btn = document.getElementById('myButton');
            btn.textContent = '更新!';
        });
    </script>
</head>

<body>
    <button id="myButton">ボタン</button>
</body>

</html>

話を戻すと

エラーになっていたスクリプトタグに「defer」を付けてみると?

<!DOCTYPE html>
<html>

<head>
    <script defer>
        // ❌ この時点ではまだ <body> 内の要素は解析されていない
        const btn = document.getElementById('myButton');
        btn.textContent = '更新!'; // btnがnullなのでエラー(TypeError)
    </script>
</head>

<body>
    <button id="myButton">ボタン</button>
</body>

</html>

変わらず、エラー。

image.png

あ、なるほど。src属性のJavaScriptにする必要があるとのこと。

src属性にしてdeferを付けると、エラーにならない!

<!DOCTYPE html>
<html>

<head>
    <script src="sample4.js" defer></script>
</head>

<body>
    <button id="myButton">ボタン</button>
</body>

</html>
const btn = document.getElementById('myButton');
btn.textContent = '更新!';

改めてdefer属性とは?

「defer」属性とは、スクリプトの実行が「DOMContentLoaded」のイベント発生前=HTMLの「文書」が完全に読み込まれてから?動くようになるのかな?

利用する際は、HTMLの文書を操作する処理がある場合は、付けておくのがよき。

とはいえ、上記観点のみであれば、スクリプトを作った人 と スクリプトを利用する人が異なると、利用する側にお任せとなるので、スクリプト内で「DOMContentLoaded」を利用し制御したほうが安全かな?

と思う。

もう少し、defer属性のメリットを深堀すると、

image.png

とあるので、Gemini解説と自身の推測から、おそらく、「読み込み前の処理」=「ダウンロード」を並列で行ってくれて、HTMLの解析を止める(= パーサーブロッキング Javscript)のを避けてくれるのかな?と。

そうすると、画面描画までの時間が短くなるメリットを理解できる。

であるなら、

スクリプトを作成する側は、HTMLの文書に依存する処理を「DOMContentLoaded」を利用し考慮。

スクリプトを利用する側は、画面のパフォーマンスを考慮し「defer」を付ける。

という棲み分けは理解できる。

とすると、基本「defer」は付けて良い気がする。

asyncとは?

image.png

defer属性と同じく、ダウンロードは並行で実施してくれる雰囲気。

実行は、defer属性とは異なり、利用可能(=ダウンロード完了?)になると直ぐに実行する感じかな?

defer属性は、HTML文書が読み込まれてから実行。
async属性は、利用可能(=ダウンロード完了?)したら実行。

と考えると、HTML文書に依存しないスクリプト かつ 早く実行したいスクリプトであれば、defer属性より、async属性のほうがよいのかな?

迷いポイントその2

「スクリプト」を書く位置ってどこが良いの?

見かけるのが、ヘッダ、ボディの末尾とか。

ヘッダ

<!DOCTYPE html>
<html>

<head>
    <script src="sample4.js"></script>
</head>

<body>
    <button id="myButton">ボタン</button>
</body>

</html>

ボディの末尾

<!DOCTYPE html>
<html>

<head>
</head>

<body>
    <button id="myButton">ボタン</button>
    <script src="sample4.js"></script>
</body>

</html>

ちゃんと考えてみると。

HTMLは上から順に読み込まれる。

defer、asyncが無いスクリプトだと、読み込まれた時点でHTMLの解析を止めて、ダウンロード、解析、実行される。

動作面で考えると

HTMLに依存しない処理であればどっちでも良い。

性能面を考えると

HTMLの解析とJavaScriptのダウンロードを並行して実施したほうがよいので、defer属性 OR async属性 を付ける。

で、早めにJavaScriptのダウンロードをさせたいので、ボディの末尾よりヘッダのほうが良い雰囲気。

まとめ

async、deferは、スクリプトのダウンロードを、HTMLの解析と並行して行うようにしてくれる。
async、deferの違いは、実行タイミングが異なる。

async:スクリプトのダウンロードが終わったら
defer:HTML文書を読み込んでから

どちらも付けていない場合は、スクリプトを発見すると、HTMLの解析を止めて、ダウンロード、解析、実行をする。

このため、ヘッダにスクリプト次第でasync OR deferを付けて定義するのが良い雰囲気。

が、そこまでパフォーマンスを意識しなくてよければ、スクリプト次第でヘッダかボディの末尾
かな。

って感じかな。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?