Tips

HTMLにJSファイルを読み込む方法と注意点【JavaScript】

  • このエントリーをはてなブックマークに追加

JavaScriptのファイルって実は読み込む場所を間違えると思ったように動作しない経験ってありませんか?

自分は最初の頃よく遭遇していて、ググってもイマイチ理解できませんでした。

本来なら読み込みについては軽くスキップせずに理解すべきなんですが、学習教材やYoutubeではそこまで触れられていません。

「コピペして書いているのに自分のパソコンだと何故か動かないときがある」
「JSファイルの読み込みの種類の意味が良く分かっていない」
「deferっていうのを見かけるけど、何のためにあるかが説明されていないと思っている」

小さなミスで時間を取られないようにJSファイルの読み込みの基本をまとめてみました。

また動画もあるので一緒に確認してもらうと良いかもしれません。

scriptタグに”defer”と書いているのは何をしているのか?

「defer」について先に説明しています。

恐らくJSファイルの読み込みで「defer」から説明しているのは珍しいと思います。

以下のようなJSファイルを用意したケースを考えます。

const div = document.getElementById("div");
console.log(div);

続いてHTMLは以下のような形にすることで上記のコードが正常に実行されます。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <link rel="stylesheet" href="./style.css" />
    <script src="./script.js" defer></script>
  </head>
  <body>
    <div id="div">hello</div>
  </body>
</html>

JavaScriptの内容としてはHTML要素を取得してコンソールに出力するだけのものです。

ここでdeferを削除してみたいと思います。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <link rel="stylesheet" href="./style.css" />
    // deferを削除した↓
    <script src="./script.js"></script>
  </head>
  <body>
    <div id="div">hello</div>
  </body>
</html>

なんとnullとなり正常に実行することができませんでした。

これがdeferの効果になります。

そもそもHTMLとJavaScriptは「上から下に向かって順番に実行していく」という性質を持っています。

①HTML側のheadタグでscript.jsを読み込む
②script.js側で「div」というidを持つ要素を取得しようとする
③①の時点では「div」というidを持つ要素はまだ登場していないのでnullになる

みたいな流れになっているんです。

ちなみにdeferがないパターンで以下のようにすると正常に動作します。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <link rel="stylesheet" href="./style.css" />
  </head>
  <body>
    <div id="div">hello</div>
    <script src="./script.js"></script>
  </body>
</html>

HTML側でscriptタグの位置をbodyタグの直前に移動させただけです。

こちらだとscript.jsを読み込む時点で、すでに「div」というidを持つ要素を発見できているので正常に動作しているのです。

まず基本的な動作を理解しておくことが大事なんですね。

deferの説明に戻りますが、deferを書くことによって簡単に言うと「JSファイルの読み込みを遅らせる」ことができます。

そのためheadタグに書いていても動作するようになっているのが冒頭の内容ということです。

すべてbodyタグの直前に書く?

「じゃあ今後はbodyタグの直前に書くようにすれば安心だ」と思われた方がいるかもしれません。

半分は正解です。

試しに先ほどのコードに新しくmain.jsというファイルを追加してみたいと思います。

console.log("test");
const div = document.getElementById("div");
console.log(div);

2つのJSファイルが存在していることになりました。

この状況で以下のようにJSファイルをheadタグで「deferなし」で読み込んでみます。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <link rel="stylesheet" href="./style.css" />
    <script src="./main.js"></script>
    <script src="./script.js"></script>
  </head>
  <body>
    <div id="div">hello</div>
  </body>
</html>

script.jsに関しては先ほど同様にnullになってしまっていますが、main.jsについては正常に動作しています。

なぜこうなるのでしょうか?

JSファイルそれぞれのコードに要因があります。

main.jsについては「testという文字をコンソールに出力する」という内容です。

「testという文字をコンソールに出力する」というのはHTML側で何か要素を見つける必要はありませんよね。

そのためheadタグでdeferがなくとも動作したわけです。

bodyタグの直前に読み込むとdeferなくとも正常に動作させることができる一方、HTMLの最後で読み込むので速度に影響を及ぼすことがあります。

今回のような簡単なコードだと大差ないですが、複雑な内容になると話は変わってきます。

そういう意味でも必ずしもbodyタグの直前が正しいということにはならないのです。

つまり状況に応じて読み込む場所を考えましょう、ということですね。

  • このエントリーをはてなブックマークに追加