benjuwan
@benjuwan

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

DOMContentLoaded と defer のどちらを使っていますか??

Discussion

Closed

そもそも JavaScript を読み込ませるには

webサイトやwebアプリでも、昨今のweb開発に無くてはならないのが JavaScript です。
JavaScriptは特性上、一旦ページ内のコンテンツ・要素を読み込まないと意図した挙動を実現できませんよね。

これまで私は JavaScript を学び始めた時の知識から、盲目的にイベントリスナーのDOMContentLoadedを使って対処してきました。

document.addEventListener("DOMContentLoaded",()=>{
    // 処理を記述
});

しかし今では、HTMLのscriptタグにあるdefer属性を使うことで JavaScript を機能させられます。

<script defer src="JavaScriptファイルのパス"></script>

スクリーンショット 2023-05-16 14.50.30.png
↑ MDN の script要素のページから defer属性の紹介部分をスクリーンショット

defer属性の位置ですが、<script defer src="JavaScriptファイルのパス">でも<script src="JavaScriptファイルのパス" defer>でも、前に記述・後ろに記述関係なく機能しました(筆者の手元のファイルでは)。

意見募集!

最近、私はdeferを使うことが多いのですが、皆さんは普段どちらを使用されていますか?
ご都合の良い際に教えていただけますと嬉しいです!
他の関連情報やご指摘などもありましたら仰ってください。

読んでいただき、ありがとうございます!

0

そもそも目的が違うし、適材適所ということだと思います。

【追記】

下に、「後で回答を編集して追加情報を書いておきます」と書いた件です。

上に書いた「そもそも目的が違う」という意味は以下の通りです。(自分の解釈込みなので異論はあるかもしれませんが)

defer

質問者さんが参考にした MDN の記事に "ブラウザーが解析を一時停止してスクリプトを読み込んで評価しなければならないようなパーサーブロック JavaScript を排除することができます" とあるように、重いスクリプトの解析に時間がかかって、それが終わるまでユーザーがページコンテンツを見ることができないという不都合を解決します。(特に header 内に script タグを配置した場合それが顕著)

ただし、"defer 属性の付いたスクリプトは、スクリプトが読み込まれて評価が完了するまで、 DOMContentLoaded イベントの発生が抑制されます" ということには注意が必要だと思います。

上記の話は、自分的には以下の記事が分かりやすいと思いましたので、紹介しておきます。

スクリプト: async, defer
https://ja.javascript.info/script-async-defer

また、古い IE での話ですが(もともと defer は IE の独自機能だったそう)、defer 属性を追加すると、あるケースで IE がそのスクリプトファイルを解析できなくなるという問題がありました。興味があれば以下の記事を見てください。

defer 属性つき script 定義と IE の問題
http://surferonwww.info/BlogEngine/post/2012/12/03/script-definition-with-defer-attribute-problem-in-internet-explorer.aspx

今の新しいブラウザではそんな問題はないのかもしれませんが(未検証・未確認です)。

DOMContentLoaded

これについては以下の記事が参考になると思います。

ページのライフサイクル: DOMContentLoaded, load, beforeunload, unload
https://ja.javascript.info/onload-ondomcontentloaded

ブラウザが HTML を完全に読み込み DOM ツリーが構築されたタイミングで、JavaScript で DOM の操作を行うためにこのイベントを利用します。

その意味で defer の目的とは異なります。

余談ですが、昔 window.onload = function() { ... } としていたのを見かけたことはありませんか? その名残で、DOMContentLoaded が適切であるのに load を使用する例を見かけます。

逆に、ブラウザがすべてのリソース(画像, スタイルなど)を読み込んだ時点で発生する load イベントを利用するのが適切というケースもあるはずです。

なので、load or DOMContentLoaded どちらが適切かもケースバーケース/適材適所だと思います。

3Like

@SurferOnWww さん
ご回答いただきありがとうございます!

私の知識不足もあって調べ直してみたところ、

HTMLの読み込みが完了しているかどうかを確認せずに呼び出すと動作不良につながるおそれがあるので、deferを使う使わないにかかわらず、「DOMContentLoaded」を使ったほうがいいのでしょうね。

というような記述を見かけました。

そもそも目的が違うし、適材適所ということだと思います。

上記のHTMLの読み込みが完了しているかどうかを確認せずに呼び出すと動作不良につながるおそれがあるという記述から @SurferOnWww さん の仰ることも漠然と理解できました(まだ足りないかもですが...)
コメントいただけたことで以前より理解が深まりましたので、教えていただきありがとうございました!

【5/18 追記】

@SurferOnWww さん
ご丁寧に編集してまで回答いただき、ありがとうございます!

恥ずかしながら上辺だけしか理解していなかったのを実感しました。
回答だけでも十分わかりやすかったのですが参考用に教えてくださったサイトも拝見し、点と点がつながって線になったような感覚です。

defer は、スクリプト(が重い場合など)の影響でページ表示速度が遅れる or 表示されづらい状態を避けたいといったアクセシビリティに考慮した性質を持っているのが特徴のひとつなんですね。

情報収集する中で他の記事に、

deferDOMContentLoadedを併用したらうまく機能しない

といったものを見たのですが、これはおそらく @SurferOnWww さん がお答えくださった MDNサイト内の記述にある

"defer 属性の付いたスクリプトは、スクリプトが読み込まれて評価が完了するまで、 DOMContentLoaded イベントの発生が抑制されます"

ということなのだろうという再発見もありました。

参考用サイトに記述されていた

DOMContentLoaded イベントはとてもシンプルです。DOM ツリーが準備できた – ここのイベントです。しかし、特徴はほとんどありません。

といった記述から、スクリプトが軽い内容でサイト構成自体もそこまで重たくないといったケースでは、DOMContentLoadedでも特に支障ないが、
スクリプトの記述 or サイト構成自体が重たい(かつドキュメント後半部にスクリプトを置いている)といったケースでは、「ページコンテンツが見れない」といった状況を避けるために(バックグラウンドで働いてくれる) deferのほうが適切、ということが分かりました。

わざわざお時間を割いてご返信及びご回答いただき、
誠にありがとうございました!

1Like

スマホで投稿してたので説明が十分でなくてすみません。後で回答を編集して追加情報を書いておきます。

1Like

Your answer might help someone💌