1. ホーム
  2. javascript

[解決済み] ページ全体が読み込まれる前に、javascriptを実行することはできますか?

2022-08-20 21:37:51

質問

ページ全体が読み込まれる前に、ちょっとしたjavascriptを実行したいのです。これは可能ですか?またはコードが実行され始めるのは </html> ?

どのように解決するのですか?

だけでなく ができる のみならず、特別な努力も必要です。 ではなく をする必要があります。)

ブラウザが古典的な script タグに遭遇すると、ブラウザはパースを中止して JavaScript インタプリタに処理を引き継ぎ、インタプリタがスクリプトを実行します。パーサーはスクリプトの実行が完了するまで処理を継続しません (スクリプトが document.write の呼び出しを行い、パーサーが処理すべきマークアップを出力する可能性があるためです)。

これはデフォルトの動作ですが、スクリプトの実行を遅らせるためのいくつかのオプションがあります。

  1. JavaScript モジュールを使用する。A type="module" スクリプトは 延期 スクリプトは、HTML が完全にパースされ、最初の DOM が作成されるまで延期されます。これはモジュールを使用する主な理由ではありませんが、理由の 1 つです。

    <script type="module" src="./my-code.js"></script>
    <!-- Or -->
    <script type="module">
    // Your code here
    </script>
    
    

    コードは (分離されていれば) 取得され、HTML のパースと並行してパースされます。 実行されます。 は実行されません。(モジュール コードがそれ自身のファイルではなくインラインである場合、それも HTML の解析が完了するまで延期されます)。

    2010 年にこの回答を最初に書いたときは、これは利用できませんでしたが、2020 年の現在では、すべての主要なモダン ブラウザがモジュールをネイティブにサポートしており、古いブラウザをサポートする必要がある場合は、Webpack や Rollup.js などのバンドラーを使用することができます。

  2. を使用します。 defer 属性を使用します。

    <script defer src="./my-code.js"></script>
    
    

    モジュールと同様に my-code.js のコードは HTML のパースと並行して取り出され、パースされますが を実行します。 は実行されません。 しかし , defer はインラインのスクリプトコンテンツでは動作しません。 src .

  3. 私はそれが何であるかは考えていません。 あなた が欲しいとは思いませんが async 属性を使用すると、HTML の解析と並行して JavaScript コードを取得し、HTML の解析が完了していなくてもできるだけ早く実行するようにブラウザに指示することができます。これを type="module" タグに記述するか、あるいは defer の代わりに使うこともできます。 script タグを使用します。

  4. を置く。 script タグをドキュメントの最後、閉じる </body> タグの直前です。

    <!doctype html>
    <html>
    <!-- ... -->
    <body>
    <!-- The document's HTML goes here -->
    <script type="module" src="./my-code.js"></script><!-- Or inline script -->
    </body>
    </html>
    
    

    こうすることで、コードが遭遇するとすぐに実行されるにもかかわらず、その上のHTMLで定義されたすべての要素が存在し、使用することができるようになるのです。

    以前は、これは一部のブラウザで追加の遅延を引き起こしていました。 script タグに遭遇するまでコードの取得を開始しないため、一部のブラウザで追加の遅延が発生していました。しかし、最近のブラウザは先にスキャンしてプリフェッチを開始します。それでも、これは現時点では非常に第三の選択肢であり、モジュールと defer はより良い選択肢です。

仕様書 には便利な図があります。 を表示します。 script タグを表示します。 defer , async , type="module" そして type="module" async と、JavaScriptのコードが取得され実行されるタイミングを指定します。

以下は、デフォルトの動作である、生の script タグの例です。

.found {
    color: green;
}
<p>Paragraph 1</p>
<script>
    if (typeof NodeList !== "undefined" && !NodeList.prototype.forEach) {
        NodeList.prototype.forEach = Array.prototype.forEach;
    }
    document.querySelectorAll("p").forEach(p => {
        p.classList.add("found");
    });
</script>
<p>Paragraph 2</p>

(参照 私の回答はこちら をご覧ください。 NodeList のコードを参照してください)。

これを実行すると、"Paragraph 1" は緑で表示されますが、"Paragraph 2" は黒です。これは、スクリプトが HTML 解析と同期して実行され、最初の段落のみを見つけ、次の段落は見つけられなかったためです。

これとは対照的に、以下は type="module" スクリプトです。

.found {
    color: green;
}
<p>Paragraph 1</p>
<script type="module">
    document.querySelectorAll("p").forEach(p => {
        p.classList.add("found");
    });
</script>
<p>Paragraph 2</p>

HTMLのパースが完了するまでコードが実行されなかったからです。これは defer script を外部コンテンツで表示することができます(インラインコンテンツは不可)。

(は必要ありませんでした)。 NodeList をチェックする必要はありません。なぜなら、モジュールをサポートしている最近のブラウザは、すでに forEach を付けているからです。 NodeList .)

この現代社会では、本当の意味で価値のない DOMContentLoaded イベントには、PrototypeJS、jQuery、ExtJS、Dojo、その他多くの企業がその昔提供していた(そして今も提供している)機能である "ready" の本当の価値はありません。単にモジュールまたは defer . 当時でさえ、これらを使用する理由はあまりありませんでした(そして、これらはしばしば間違った方法で使用され、jQuery ライブラリ全体がロードされる間、ページ表示が保持されました。 scripthead の中ではなく、ドキュメントの後)、何か Google の一部の開発者は の一部の開発者が早い段階で指摘したことです。また、これは YUI の推奨 の末尾にスクリプトを置くことを推奨した理由のひとつでもあります。 body を使用することを推奨しています。