web-dev-qa-db-fra.com

Comment fonctionne exactement <script defer = "defer">?

J'ai quelques éléments <script> et le code de certains d'entre eux dépend du code des autres éléments <script>. J'ai vu que l'attribut defer peut être utile ici car il permet de reporter l'exécution de blocs de code.

Pour le tester, je l'ai exécuté sur Chrome: http://jsfiddle.net/xXZMN/ .

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

Cependant, il alerte 2 - 1 - 3. Pourquoi ne pas alerter 1 - 2 - 3?

200
pimvdb

MISE À JOUR: 19/02/2016

Considérez cette réponse obsolète. Reportez-vous aux autres réponses à ce message pour des informations relatives à la nouvelle version du navigateur.


Fondamentalement, différer indique au navigateur d'attendre "jusqu'à ce qu'il soit prêt" avant d'exécuter le javascript dans ce bloc de script. Cela se produit généralement après le chargement du DOM et de document.readyState == 4.

L'attribut différer est spécifique à Internet Explorer. Dans Internet Explorer 8, sous Windows 7, le résultat affiché dans votre page de test JS Fiddle est le suivant: 1 - 2 - 3.

Les résultats peuvent varier d'un navigateur à l'autre.

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

Contrairement à la croyance populaire, IE respecte plus les normes que les utilisateurs, l'attribut "différer" est défini dans la spécification DOM niveau 1 http://www.w3.org/TR /REC-DOM-Level-1/level-one-html.html

La définition de différer donnée par le W3C: http://www.w3.org/TR/REC-html40/interact/scripts.html#adef-defer :

"Lorsqu'il est défini, cet attribut booléen indique à l'agent utilisateur que le script ne va générer aucun contenu de document (par exemple, pas de" document.write "en javascript) et que, par conséquent, l'agent utilisateur peut poursuivre l'analyse et le rendu."

50
Mark At Ramp51

Quelques extraits de la spécification HTML5: http://w3c.github.io/html/semantics-scripting.html#element-attrdef-script-async

Les attributs defer et async ne doivent pas être spécifiés si l'attribut src n'est pas présent.


Trois modes possibles peuvent être sélectionnés à l'aide de ces attributs [async et différer]. Si l'attribut async est présent, le script sera exécuté de manière asynchrone dès qu'il sera disponible. Si l'attribut asynchrone n'est pas présent mais que l'attribut de différer est présent, le script est exécuté lorsque l'analyse de la page est terminée. Si aucun attribut n'est présent, le script est extrait et exécuté immédiatement avant que l'agent utilisateur ne continue d'analyser la page.


Les détails de traitement exacts de ces attributs sont, pour la plupart des raisons historiques, quelque peu non triviaux et concernent plusieurs aspects du HTML. Les exigences de mise en œuvre sont donc nécessairement dispersées dans toute la spécification. Les algorithmes ci-dessous (dans cette section) décrivent le cœur de ce traitement, mais ces algorithmes sont référencés et référencés par les règles d'analyse des balises de début et de fin de script en HTML, en contenu étranger et en XML, les règles du document.write. (), le traitement des scripts, etc.


Si l'élément a un attribut src et que l'élément a un attribut différer et que l'élément a été marqué comme "parser-inséré" et que l'élément n'a pas d'attribut asynchrone:

L'élément doit être ajouté à la fin de la liste des scripts à exécuter lorsque l'analyse du document est terminée, associée au document de l'analyseur qui a créé l'élément.

162
Alohci

La vraie réponse est: Parce que vous ne pouvez pas faire confiance différer.

En principe, différer et async diffèrent comme suit:

async permet de télécharger le script en arrière-plan sans le bloquer. Ensuite, dès que le téléchargement est terminé, le rendu est bloqué et le script est exécuté. Le rendu reprend lorsque le script est exécuté.

différer fait la même chose, sauf prétendre garantir que les scripts s'exécutent dans l'ordre dans lequel ils ont été spécifiés sur la page et qu'ils seront exécutés après le document. a terminé l'analyse. Ainsi, certains scripts peuvent terminer le téléchargement, puis attendre les scripts téléchargés plus tard, mais parus avant eux.

Malheureusement, en raison de ce qu’il s’agit vraiment d’un combat de normes, la définition de différer varie d’une spécification à l’autre, et même dans les spécifications les plus récentes, elle n’offre pas une garantie utile. Comme les réponses ici et ce numéro démontrent, les navigateurs implémentent différer différemment:

  • Dans certaines situations, certains navigateurs ont un bogue qui provoque le dysfonctionnement des scripts defer.
  • Certains navigateurs retardent l’événement DOMContentLoaded jusqu’à ce que les scripts defer aient été chargés et d’autres pas.
  • Certains navigateurs obéissent à defer sur <script> éléments avec code intégré et sans attribut src, et certains l'ignorent.

Heureusement, la spécification indique au moins que l’async remplace le différé. Vous pouvez donc traiter tous les scripts comme étant asynchrones et bénéficier d'un large éventail de supports de navigateurs, comme ceci:

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

98% des navigateurs utilisés dans le monde et 99% aux États-Unis éviteront le blocage avec cette approche.

(Si vous devez attendre que l'analyse du document soit terminée, écoutez l'événement DOMContentLoaded ou utilisez la fonction pratique .ready() de jQuery. Vous souhaiterez néanmoins le faire sans avoir recours aux navigateurs non implémentés defer du tout.)

155
Chris Moschini

defer ne peut être utilisé que dans la balise <script> pour script externe inclusion. Par conséquent, il est conseillé de l'utiliser dans les balises <script>- de la section <head>-.

13
Rajesh Paul

Comme l'attribut defer ne fonctionne qu'avec la balise scripts avec src Trouver un moyen d'imiter différer les scripts en ligne. Utilisez l'événement DOMContentLoaded.

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

En effet, l'événement DOMContentLoaded est déclenché après le chargement complet des scripts attribués différés.

7
Bijoy Anupam

L'attribut deffer ne concerne que les scripts externes (ne doit être utilisé que si l'attribut src est présent).

6
Soumitra

Il convient également de noter qu’il pourrait y avoir des problèmes dans IE <= 9 lorsqu’on utilise script defer dans certaines situations. Plus sur ceci: https://github.com/h5bp/lazyweb-requests/issues/42

4
Maxim

Jetez un oeil à cet excellent article Plongez profondément dans les eaux troubles du chargement des scripts par le développeur de Google, Jake Archibald, écrit en 2013.

Citant la section pertinente de cet article:

Reporter

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

Spec dit : Télécharger ensemble, exécuter dans l'ordre juste avant DOMContentLoaded. Ignore "différer" les scripts sans "src".

IE <10 dit : Je pourrais exécuter 2.js à mi-chemin de l'exécution de 1.js. N’est-ce pas amusant ??

Les navigateurs en rouge dire : Je n'ai aucune idée de ce que cette "différer" est, je vais charger le des scripts comme s'il n'y en avait pas.

Les autres navigateurs disent : D'accord, mais je ne pourrais pas ignorer "différer" les scripts sans "src".

(J'ajouterai que les premières versions de Firefox déclenchent DOMContentLoaded avant que les scripts defer finissent de s'exécuter, selon ce commentaire .)

Les navigateurs modernes semblent supporter correctement async, mais vous devez être OK avec des scripts en cours d'exécution et éventuellement avant DOMContentLoaded.

4
Flimm

Cet attribut booléen est défini pour indiquer à un navigateur que le script doit être exécuté après l'analyse du document. Cette fonctionnalité n’ayant pas encore été implémentée par tous les autres principaux navigateurs, les auteurs ne doivent pas présumer que l’exécution du script sera en fait différée. N'appelez jamais document.write () à partir d'un script de report (depuis Gecko 1.9.2, le document disparaîtra). L'attribut de report ne doit pas être utilisé sur des scripts qui n'ont pas l'attribut src. Depuis Gecko 1.9.2, l'attribut de report est ignoré pour les scripts ne possédant pas l'attribut src. Cependant, dans Gecko 1.9.1, même les scripts en ligne sont différés si l’attribut de report est défini.

defer fonctionne avec chrome, firefox, c'est-à-dire> 7 et Safari

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

1
s-sharma

L'attribut différer est un attribut booléen.

Lorsqu'il est présent, il spécifie que le script est exécuté lorsque l'analyse de la page est terminée.

Remarque: L'attribut deffer concerne uniquement les scripts externes (ne doit être utilisé que si l'attribut src est présent).

Remarque: Un script externe peut être exécuté de plusieurs manières:

Si async est présent: le script est exécuté de manière asynchrone avec le reste de la page (le script sera exécuté tant que la page poursuivra l'analyse) Si async n'est pas présent et différé est présent: le script est exécuté lorsque l'analyse de la page est terminée Si ni asynchrone ni différé n'est présent: le script est récupéré et exécuté immédiatement, avant que le navigateur ne poursuive l'analyse de la page

0
srikanth_k