JavaScriptの<script>タグ内に付けることでスクリプトを非同期で読み込ませることができるasync属性とdefer属性についてです。
この属性を使用すればレンダリングブロックが回避できてページ読み込みが高速になるのですが、最大限に使うためにはいくつかポイントがあります。
<script>タグはフッター(/body直前)に設置した方がページ読み込みが高速になるという話が有名ですが、全てがその限りではないことに注意が必要です。
技術者ではない自分が今まで盲点になっていた内容もご紹介します。
この記事の目次
非同期読み込み属性:async・deferについて
まずHTMLのパース(解析)とレンダリングブロックについて触れておきます。
Webブラウザがページを読み込む時にはHTMLを記述順に解析(パース)します。
ページソースの上から下に向かって順番に読んでいくので、人と同じ感じです。
ブラウザはHTMLを解析している途中でscript要素を見つけると、解析を一時中断し、スクリプトの確認と実行を先に行います。
その処理が終わった後、再び中断していた解析に戻るというのが基本的な流れです。
jsの準備→実行と、scriptタグがある度にHTMLの解析が中断されます。
このHTMLの解析を中断させてしまうのがレンダリングブロックという現象です。
レンダリング(画面の描画)+ブロック(妨害)でそのままの意味です。
scriptを見つけるたびにHTMLの解析がストップしてしまい、ページの読み込みが遅くなってしまうという問題です。
このレンダリングブロックの対処法として有名なのがフッター読み込みです。
上から下へ解析していくなら、ページの後半にあたるフッター部分(/body直前)にscriptを設置することでHTMLの解析を中断させることなく進め、ページの読み込みを改善しようという考えです。
シンプルな方法ですが効果があります。
フッター読み込みはスクリプトの疑似的な遅延読み込みと言えそうですね。
時代が進むとWebブラウザも進化し、HTMLの解析と非同期的に(並行しながら)scriptの解析も行えるようになりました。
そこで登場したのがasyncとdefer属性です。
読み方は「エイシンク」と「デファー」らしいです。ややこしい...
<script>タグにこの属性があるとブラウザはHTMLの途中でscript要素に辿り着いても立ち止まることなく解析を続けるため、スムーズな読み込みができます。
ポイント
【scriptのフッター読み込み】
HTMLは上から解析されるため、解析を中断してしまうリソースをページ下部に設置することで読み込みをスムーズにする方法。
【async・deferの役割】
HTMLの解析途中でscriptタグを見つけても処理を待たずに解析を続けて下さいというブラウザへの指令。
どちらもページ読み込み速度の改善に関する内容ですが、やっていることは別です。
ややこしいね・w・
asyncとdeferの違い
asyncとdeferはどちらもブラウザにscriptを非同期で読み込ませるための属性です。
ややこしいですが、非同期で行われるのはscriptの読み込みのみです。
scriptを実行する時にはHTMLの解析は一旦中断されます。
実行中にページの読み込みが遅くなるのは仕方がないということですね。
とはいえ、どちらを使ってもレンダリングブロックは回避できます。
ではasyncとdeferはどう違うのか?
この2つの違いはどのタイミングでscriptを実行するかです。
ポイント
- async:リソース読み込み直後に実行。
- defer:HTML解析終了後に実行。
asyncは日本語で「非同期」、deferは日本語で「延期」です。
asyncはscriptの読み込みが完了した時点ですぐに実行されます。
処理する準備ができ次第HTMLの解析を止めて実行する感じです。
deferの場合はscriptの読み込みが完了してもすぐには実行されません。
HTMLの解析が完了した後に実行されます。まさに延期という言葉がピッタリ!
ページ読み込みの最後の方で実行される感じですね。
asyncは読み込みが完了したscriptから実行されるので実行順がバラバラになります。
deferの場合は同じdeferを付与したscriptの記述順(上から順番)に実行されます。
このことを念頭に置いて使い方を見ていきましょう!
asyncとdeferの使い方
asyncもdeferも使い方は非常に簡単!
<script>タグの中に記述すればそれでOKです。あとはブラウザがやってくれます。
属性なのでタグの中ならどこでも良いです。
(例1)
<script async src="○○.js"></script>
scriptのすぐ後ろが分かりやすいかな?
(例2)
<script src="○○.js" async></script>
一番最後でも全く問題なし!
例ではasyncですが、deferも同じです。
注意ポイント
使うのは簡単ですが、コードの改変にあたる可能性があります。
広告関係のコードには始めから入っていると思いますがご注意を。
type="text/javascript"がない時
ここで少し脱線。
「<script type="text/javascript"~>」という書き方はよく見ます。
が、たまにtype="text/javascript"の記述がない場合があります。
これ最近まで知らなかったのですが、HTML5からはtype属性を省略した場合は初期値が"text/javascript"になるらしいです。
未だにHTML4を考慮してか書くのが一般的ですが、実は無くても良いです。
ついでに知っておきたい豆知識でした。
どちらを使えばよいか?
asyncやdeferでレンダリングブロックは回避できるけど、該当するscriptにどちらを指定して良いか分からない場合があります。
asyncは実行順が不明ですので、外部のデータだけで動作できるものに使用します。
例えば、広告サービスだったりアクセス解析に使うスクリプトです。
これらは単独で動作するのでいつ実行されても問題ないからです。
またdeferではページが読み込まれた後に実行され、遅すぎるという意味もあります。
deferは依存関係があるscriptを非同期読み込みしたい場合に使います。
あるスクリプトを読み込んでいることを前提に作られたプログラムなどですね。
また、DOM操作を行うスクリプト等はDOM完成後に読み込まないとうまく動かないことがあります。
とにかく読み込み順が逆になるとエラーになってしまうスクリプトにはお互いにdeferを指定し、実行したい順番で記述しないとダメです。
jQueryを使ったスクリプトも依存関係がある可能性が高いですが、影響範囲が大きすぎるjQuery本体にはdeferは使わない方が良いです。
ポイント
【asyncが良いスクリプト】
- 広告サービス
- アクセス解析ツール
- SNSなどのツール
【deferが良いスクリプト】
- 依存関係のあるスクリプト
分からない場合はもれなくdeferを付けると一応実行順通りには動くはずです。
※動作確認必須。
asyncとdeferを両方書いた場合
よく悩みそうな内容で、asyncとdeferのどちらを使えばよいか分からない!
じゃあ両方書いてブラウザに任せたらどう?という話です。
(例)
<script async defer src="○○.js"></script>
こんな感じに両方書いた場合ですね。
少し調べたところ、asyncとdeferの両方を記述してある時は、asyncに対応している場合はasync。対応していない場合にはdefer扱いとなるようです。
今現在asyncに対応していないブラウザは無いと考えてOKですので、意図的にどちらかを記述する方が望ましいです。
どちらも記述しているサイトを見たことがないのでやらない方が良いのでしょう。
scriptタグ内にsrc属性がないと効果なし!
asyncとdeferはどちらもscript要素にsrc属性を指定した場合だけ指定できます。
外部リソースに対してのみ有効な属性ということです。
たまにカスタマイズ用のJavaScriptのコードをbodyに埋め込んでいて、このscriptタグの中にasyncやdeferを書いてあるところがありますが、意味がないらしいです。
内部リソースに対して指定しても効果がないだけでエラーなどは出ませんが…
僕はこの事実を知る前はasyncやdeferが付いていないscriptタグを見つけるなり追記していたのですが、意味なしだったようです・w・
体感で全然速くならねぇ~と思ったりはしてたんですが¥w¥
何でもかんでも書けば良い、マネすれば良いという訳ではないですね…
async・deferを付けたらヘッダーで読み込む
これもやってしまいがちなミスです。
asyncやdeferが付いている<script>を更にフッター付近(/body直前等)で読み込んでしまっている場合は改善の余地ありです。
冒頭にも書いた通り、scriptの設置個所をヘッダー(head内)からフッター(body内)に変更することはページ読み込みスピードの改善として非常に有名な内容です。
ですが、本来フッター読み込みは<script>タグにasyncもdeferも付けていない場合の改善方法です。
asyncやdeferを付けると、ブラウザはHTMLの解析中にscriptタグに辿り着いた時点でスクリプトの読み込み(準備)と並行して解析を進め、準備が整った直後(async)またはページの解析終了時(defer)にスクリプトを実行するという話でした。
ところがフッター付近はHTMLの解析終了間際の位置です。
解析終盤でscriptを見つけ、そこから非同期読み込みを開始してもページの読み込みはほとんど完了してしまっているため、非同期読み込みの利点を生かせません。
scriptタグの検出は非同期読み込みの開始です。
出来るだけ早くscriptの準備をしてもらう為にもasyncやdeferが付いた<script>タグはヘッダー(head内)で読み込む方が良いです。
まとめ
asyncとdeferの違いと使用時のポイントをまとめてみました。
コーディングしているとよく見かけるけど、勉強すると意外と知らないことだらけだったので記事にしました。
改めてページのソースを見るとWordpressのプラグインなんかはフッター読み込みが基本になっていて、そのコードを見るとasyncは一切ついていません。
プラグインの開発者の方からしたら"あたりまえ"なのか...
ではではこのへんで・w・
最後に
数日かけて勉強し、テストもそれなりにしたのですが、この分野の専門家ではないので何か間違いがあればご指摘いただけると助かります。