最近の web サイトでは、スクリプトは HTML よりも “重い” ことがしばしばです: ダウンロードサイズはより大きく、処理時間も長くなります。
ブラウザが HTML をロードし、<script>...</script> タグに遭遇すると、DOM の構築を続けることはできません。すぐにスクリプトを実行する必要があります。外部スクリプト <script src="..."></script> についても同じです: ブラウザはスクリプトをダウンロードし、それを実行するまで待つ必要があり、その後にページの残り部分の処理をすることになります。
これは2つの重要な問題につながります:
- スクリプトは、それ以降の DOM要素は認識することができないため、ハンドラーを追加したりすることはできません。
- ページの先頭に重いスクリプトがあると、“ページをブロック” します。利用者はそれがダウンロードされ実行されるまでページコンテンツを見ることができません:
<p>...content before script...</p>
<script src="https://javascript.info/article/script-async-defer/long.js?speed=1"></script>
<!-- スクリプトがロードされるまで表示されません -->
<p>...content after script...</p>
回避策はいくつかあります。例えば、ページの末尾にスクリプトを置きます。すると要素を表示でき、ページコンテンツの表示をブロックしません:
<body>
...all content is above the script...
<script src="https://javascript.info/article/script-async-defer/long.js?speed=1"></script>
</body>
ですが、この方法は完璧には程遠いです。例えば、ブラウザが完全なHTMLドキュメントをダウンロードした後にのみスクリプトに気づき(、ダウロードが開始でき)ます。HTML ドキュメントが長いと、かなりの遅延になる可能性があります。
このようなことは、十分に早い接続を使用している人々には見えませんが、世界中の多くの人は依然として低速のインターネットを利用しており、完璧とはほど遠いモバイルインターネット接続を使用しています。
幸いなことに、この問題を解決する2つの <script> 属性があります: defer と async です。
defer
defer 属性はブラウザにスクリプトを待たないよう指示します。代わりに、ブラウザは HTML の処理を継続し、DOM を構築します。スクリプトは “バックグラウンド” でロードされ、DOM が完全に構築されたときに実行されます。
これは上記と同じ例ですが、defer を指定しています:
<p>...content before script...</p>
<script defer src="https://javascript.info/article/script-async-defer/long.js?speed=1"></script>
<!-- すぐに表示されます -->
<p>...content after script...</p>