web-dev-qa-db-ja.com

<script defer = "defer">はどのように機能しますか?

<script>要素がいくつかあり、そのうちのいくつかのコードは他の<script>要素のコードに依存しています。 defer属性は、コードブロックの実行を延期できるため、ここで便利になることがわかりました。

それをテストするために、Chromeでこれを実行しました: http://jsfiddle.net/xXZMN/

<script defer="defer">alert(2);</script>
<script>alert(1)</script>
<script defer="defer">alert(3);</script>

ただし、2 - 1 - 3に警告します。なぜ1 - 2 - 3に警告しないのですか?

200
pimvdb

更新日:2016年2月19日

この答えは時代遅れだと考えてください。新しいブラウザーバージョンに関連する情報については、この投稿の他の回答を参照してください。


基本的に、deferは、そのスクリプトブロックでjavascriptを実行する前に「準備ができるまで」待つようにブラウザに指示します。通常、これはDOMの読み込みとdocument.readyState == 4が完了した後です。

Defer属性はInternet Explorerに固有です。 Internet Explorer 8では、Windows 7で、JS Fiddleテストページに表示される結果は、1-2-3です。

結果はブラウザごとに異なる場合があります。

http://msdn.Microsoft.com/en-us/library/ms533719(v = vs.85).aspx

一般的な信念に反して、IEは人々がやるよりも頻繁に標準に従いますが、実際には「遅延」属性はDOMレベル1仕様で定義されています http://www.w3.org/TR /REC-DOM-Level-1/level-one-html.html

W3Cのdeferの定義: http://www.w3.org/TR/REC-html40/interact/scripts.html#adef-defer

「設定されると、このブール属性は、スクリプトがドキュメントコンテンツを生成しないというヒントをユーザーエージェントに提供します(たとえば、javascriptに "document.write"はありません)。したがって、ユーザーエージェントは解析とレンダリングを続行できます。」

50
Mark At Ramp51

HTML5仕様からの抜粋: http://w3c.github.io/html/semantics-scripting.html#element-attrdef-script-async

Src属性が存在しない場合は、deferおよびasync属性を指定しないでください。


これらの属性[非同期および遅延]を使用して選択できる3つのモードがあります。 async属性が存在する場合、スクリプトは利用可能になるとすぐに非同期で実行されます。 async属性は存在せず、defer属性は存在する場合、ページの解析が完了するとスクリプトが実行されます。どちらの属性も存在しない場合、ユーザーエージェントがページの解析を続行する前に、スクリプトがすぐにフェッチされて実行されます。


これらの属性の正確な処理の詳細は、主に歴史的な理由から、HTMLの多くの側面に関係する、やや自明ではありません。したがって、実装要件は必然的に仕様全体に散在しています。以下のアルゴリズム(このセクション)では、この処理のコアについて説明しますが、これらのアルゴリズムは、HTML、外部コンテンツ、およびXMLのスクリプト開始タグと終了タグの解析ルールによって参照され、ドキュメントのルールによって参照されます。 ()メソッド、スクリプトの処理など。


要素にsrc属性があり、要素にdefer属性があり、要素に「parser-inserted」というフラグが付けられていて、要素にasync属性がない場合:

要素は、要素を作成したパーサーのドキュメントに関連付けられたドキュメントの解析が完了したときに実行されるスクリプトのリストの最後に追加する必要があります。

162
Alohci

本当の答えは、延期を信頼できないからです。

概念的には、deferとasyncは次のように異なります。

asyncは、ブロックせずにスクリプトをバックグラウンドでダウンロードできるようにします。その後、ダウンロードが終了すると、レンダリングがブロックされ、そのスクリプトが実行されます。スクリプトが実行されると、レンダリングが再開されます。

deferは同じことを行いますが、スクリプトはページで指定された順序で実行され、ドキュメントの後に実行されることを保証するという主張を除きます解析が終了しました。そのため、一部のスクリプトはダウンロードを終了してから、後でダウンロードしたがそれらの前に表示されたスクリプトを待機します。

残念ながら、実際に標準的な猫の戦いであるため、延期の定義は仕様ごとに異なり、最新の仕様でさえ有用な保証を提供していません。答え ここ および この問題 が示すように、ブラウザーは遅延を異なる方法で実装します。

  • 特定の状況では、一部のブラウザーには、deferスクリプトが順不同で実行されるバグがあります。
  • 一部のブラウザーは、DOMContentLoadedスクリプトがロードされるまでdeferイベントを遅延させますが、そうしないブラウザーもあります。
  • 一部のブラウザは、インラインコードを使用し、defer属性を持たない<script>要素でsrcに従いますが、無視するブラウザもあります。

幸いなことに、この仕様は少なくとも非同期が遅延をオーバーライドすることを指定しています。したがって、すべてのスクリプトを非同期として処理し、次のように広範なブラウザーサポートを取得できます。

<script defer async src="..."></script>

世界中で使用されているブラウザの98%、および米国で99%のブラウザは、このアプローチでブロックを回避します。

(ドキュメントの解析が完了するまで待つ必要がある場合は、イベントDOMContentLoadedイベントをリッスンするか、jQueryの便利な.ready()関数を使用します。とにかくこれを実行して、deferをまったく実装しないブラウザーでフォールバックします。)

155
Chris Moschini

deferは、外部スクリプトを含めるために<script>タグでのみ使用できます。したがって、<script>セクションの<head>- tagsで使用することをお勧めします。

13
Rajesh Paul

Defer属性は、srcのスクリプトタグでのみ機能するためインラインスクリプトの遅延を模倣する方法を見つけました。 DOMContentLoadedイベントを使用します。

<script defer src="external-script.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function(event) {
    // Your inline scripts which uses methods from external-scripts.
});
</script>

これは、遅延属性のスクリプトが完全にロードされた後にDOMContentLoadedイベントが発生するためです。

7
Bijoy Anupam

Defer属性は外部スクリプト専用です(src属性が存在する場合にのみ使用してください)。

6
Soumitra

特定の状況でscript deferを使用すると、IE <= 9で問題が発生する可能性があることにも注意してください。詳細: https://github.com/h5bp/lazyweb-requests/issues/42

4
Maxim

この素晴らしい記事をご覧ください スクリプトロードの濁った海に深く潜り込みます 2013年に書かれたGoogle開発者Jake Archibaldによる。

その記事の関連セクションを引用:

延期する

<script src="//other-domain.com/1.js" defer></script>
<script src="2.js" defer></script>

Spec says:一緒にダウンロードし、DOMContentLoadedの直前に順番に実行します。 「src」なしでスクリプトの「遅延」を無視します。

IE <10 says:1.jsの実行の途中で2.jsを実行するかもしれません。面白くないですか??

赤のブラウザ say:この「延期」の内容がわからないので、あたかも存在しないかのようにスクリプト。

他のブラウザは言う:わかりましたが、「src」のないスクリプトの「defer」を無視しないかもしれません。

deferスクリプトの実行が終了する前に、Firefoxの初期バージョンがDOMContentLoadedをトリガーすることを追加します このコメントによる 。)

最近のブラウザはasyncを適切にサポートしているように見えますが、スクリプトが順不同で、場合によってはDOMContentLoadedの前に実行される必要があります。

4
Flimm

このブール属性は、ドキュメントが解析された後にスクリプトが実行されることをブラウザに示すために設定されます。この機能は他のすべての主要なブラウザではまだ実装されていないため、作成者はスクリプトの実行が実際に延期されると想定しないでください。延期スクリプトからdocument.write()を呼び出さないでください(Gecko 1.9.2以降、ドキュメントが吹き飛ばされます)。 defer属性は、src属性を持たないスクリプトでは使用しないでください。 Gecko 1.9.2以降、src属性を持たないスクリプトではdefer属性は無視されます。ただし、Gecko 1.9.1では、defer属性が設定されている場合、インラインスクリプトも延期されます。

deferはchrome、firefox、つまり> 7およびSafariで動作します

参照: https://developer.mozilla.org/en-US/docs/HTML/Element/script

1
s-sharma

Defer属性はブール属性です。

存在する場合、ページの解析が終了したときにスクリプトが実行されることを指定します。

注:defer属性は外部スクリプト専用です(src属性が存在する場合にのみ使用してください)。

注:外部スクリプトを実行する方法はいくつかあります。

非同期が存在する場合:スクリプトはページの残りの部分と非同期で実行されます(スクリプトはページが解析を続行している間に実行されます)非同期が存在せず、延期が存在する場合:スクリプトはページの解析が終了したときに実行されます非同期も遅延もありません:ブラウザがページの解析を続ける前に、スクリプトがすぐにフェッチされて実行されます

0
srikanth_k