pyてよn日記

一寸先は闇が人生

JavaScript:同期 / 非同期な読み込みの注意点 - スクリプトの依存関係

導入

Webページの読み込みにおける、JavaScriptファイルの非同期実行の注意点に関してまとめました。

Webページ読み込み時のJavaScriptファイルの挙動:同期的・非同期的な実行

 HTMLファイルの描画中に script 要素(<script>タグ)があると、 HTML のパースが止まり、指定されたJavaScript ファイルのパース・実行が終わるまで HTML は読み込まれない。このような実行形式を JavaScript ファイルの同期実行と呼ぶ。同期実行の問題点は、JavaScript ファイル内に重い処理があるときにその処理が終わるまで Web ページが表示されないという点で、これはユーザにとってストレスになりうる。その問題の解決方法としては、

  • body 要素の直前に script 要素をおく
  • script 要素にasync属性を付けることによる JavaScript ファイルの非同期実行

などが挙げられる。以下では、二つ目の非同期実行の注意点を説明する。

非同期実行の注意点:スクリプトの依存関係

 src 属性指定された、async 属性付きの script要素 は非同期にロードされ(HTMLのパースがストップしない)、JavaScript ファイルのパースが完了次第順次実行される。そのため同期実行時よりもWeb ページの読み込み速度が上がる。しかし注意点として、async 属性付きの script 要素はその性質上、実行順序が保証されないということが挙げられる。(async / defer 属性は、src 属性を持つ script 要素にしか使えないことにも注意)

 以下のようなコードで、app.jslib.jsに依存している場合を考える。どちらの script 要素にも async 属性を付けてあるため、どちらが先に実行されるか分からず、実行順序によってはapp.jsが正しく動作しない可能性がある。

<!-- 実行順序が保証されない -->
<script async src="js/lib.js"></script>
<script async src="js/app.js"></script>

この問題の解決策としては、

  • 依存関係になる.jsファイルをあらかじめ1つにまとめる
  • async 属性の代わりにdefer属性を指定する

が挙げられる。defer 属性は、スクリプトの実行をhtmlのパース終了後まで遅延させることを指示する script 要素の属性である。head 要素内と body 要素内に script 要素があり、相互に async / defer 属性があるときは依存関係に気をつけて、何度もテストしてみた方がよい。というよりは、async / defer 属性を使用する場合は head 要素内で script 要素を記述することを心掛けた方が良いと思われる。

 また、async / defer 属性が指定された script 要素がdocument.write()メソッドを含んでいる場合、DOMの構築との不具合と思われるが、属性の指定は無効になり通常の script 要素として扱われ同期実行となる( document.write() はページが一旦クリアされてしまうため?(そもそも非推奨)、document.textContentdocument.innerHTMLを優先して利用すべき)。また、async / defer 属性の対応していないブラウザ上でも同じように属性指定は無効になることも注意すべきである。

終わりに

 本記事は、筆者の知識不足のため正確ではない部分があると思います。もし訂正・指摘等ありましたらコメント・DM等お願い致します。同期・非同期処理すら知らなかったので本記事の内容自体へーって感じでした。最近はWebページの挙動について勉強していて、HTML&CSSJavaScript等々理解すべきことが多いですが地道に頑張らないとなという思いです。
 数学の勉強がなかなか進んでいなことがストレスになっていてあまり精神状態が良くなく、目に見えやすいWebの勉強に逃げてしまっている面はありますがめげずにやっていきます(Webが簡単ということを言いたいわけではないです)。

参考