Balise de script - async et différé

548

J'ai quelques questions sur les attributs asyncet deferla <script>balise qui, à ma connaissance, ne fonctionnent que dans les navigateurs HTML5.

Un de mes sites a deux fichiers JavaScript externes qui se trouvent actuellement juste au-dessus de la </body>balise; le premier est provenant de google et le second est un script externe local.

En ce qui concerne la vitesse de chargement du site

  1. Y a-t-il un avantage à ajouter asyncaux deux scripts que j'ai en bas de la page?

  2. Y aurait-il un avantage à ajouter l' asyncoption aux deux scripts et à les placer en haut de la page dans le <head>?

  3. Cela signifierait-il qu'ils téléchargent au fur et à mesure que la page se charge?
  4. Je suppose que cela entraînerait des retards pour les navigateurs HTML4, mais cela accélérerait-il le chargement des pages pour les navigateurs HTML5?

En utilisant <script defer src=...

  1. Le chargement des deux scripts à l'intérieur <head>avec l'attribut aurait-il deferle même effet que d'avoir les scripts avant </body>?
  2. Encore une fois, je suppose que cela ralentirait les navigateurs HTML4.

En utilisant <script async src=...

Si j'ai deux scripts avec asyncactivé

  1. Voudraient-ils télécharger en même temps?
  2. Ou un à la fois avec le reste de la page?
  3. L'ordre des scripts devient-il alors un problème? Par exemple, un script dépend de l'autre, donc si un téléchargement est plus rapide, le second peut ne pas s'exécuter correctement, etc.

Enfin, est-il préférable de laisser les choses telles qu'elles sont jusqu'à ce que HTML5 soit plus couramment utilisé?

Adam
la source
5
asyncest nouveau (ish), mais deferfait partie d'IE depuis IE4. defera été ajouté à d'autres navigateurs beaucoup plus récemment, mais les anciennes versions de ces navigateurs ont tendance à beaucoup moins traîner.
Alohci
3
Maintenant, HTML5 est devenu très populaire!
septembre 2018 à 8h41
2
deferrevient à placer des scripts au bas du code HTML, ce qui est courant depuis de nombreuses années.
vsync
1
@vsync n'est pas nécessairement vrai, le navigateur téléchargera le JS avec la balise defer lorsqu'il analysera la balise de script, mais différera l'exécution jusqu'à juste avant DOMContentLoaded. Le téléchargement n'est pas bloquant. Placer au bas du HTML retardera le téléchargement et l'exécution du JS jusqu'à ce que le DOM soit construit, mais vous encourrez toujours un délai supplémentaire en attendant le téléchargement.
Brad Frost
@BradFrost - Le téléchargement est bloquant à mon avis, dans le sens où cela prend de la bande passante Internet, et pour ceux avec une connexion lente, je considère qu'il est impératif de charger d'abord le document et ensuite seulement, une fois rendu, de commencer à télécharger des fichiers javascript . Cela est vrai dans les cas où le contenu n'est pas étroitement couplé à javascript pour tout rendre (comme SPA )
vsync

Réponses:

406

Conservez vos scripts juste avant </body>. Async peut être utilisé avec des scripts qui s'y trouvent dans quelques circonstances (voir la discussion ci-dessous). Le report ne fera pas beaucoup de différence pour les scripts qui s'y trouvent, car le travail d'analyse DOM a déjà été fait de toute façon.

Voici un article qui explique la différence entre async et defer: http://peter.sh/experiments/asynchronous-and-deferred-javascript-execution-explained/ .

Votre code HTML s'affichera plus rapidement dans les anciens navigateurs si vous conservez les scripts à la fin du corps juste avant </body>. Donc, pour conserver la vitesse de chargement dans les anciens navigateurs, vous ne voulez pas les placer ailleurs.

Si votre deuxième script dépend du premier script (par exemple, votre deuxième script utilise le jQuery chargé dans le premier script), vous ne pouvez pas les faire asynchroniser sans code supplémentaire pour contrôler l'ordre d'exécution, mais vous pouvez les faire différer car les scripts différés toujours être exécutées dans l'ordre, juste après l'analyse du document. Si vous disposez de ce code et que vous n'avez pas besoin que les scripts s'exécutent immédiatement, vous pouvez les rendre asynchrones ou différés.

Vous pouvez mettre les scripts dans la <head>balise et les définir deferet le chargement des scripts sera différé jusqu'à ce que le DOM ait été analysé et cela affichera rapidement la page dans de nouveaux navigateurs qui prennent en charge le report, mais cela ne vous aidera pas du tout dans les anciens navigateurs et ce n'est pas vraiment plus rapide que de simplement placer les scripts juste avant </body>ce qui fonctionne dans tous les navigateurs. Donc, vous pouvez voir pourquoi il est préférable de les mettre juste avant </body>.

Async est plus utile lorsque vous ne vous souciez vraiment pas du chargement du script et rien d'autre qui dépend de l'utilisateur dépend du chargement de ce script. L'exemple le plus souvent cité pour utiliser async est un script d'analyse comme Google Analytics que vous ne voulez rien attendre et qu'il n'est pas urgent de s'exécuter rapidement et il est autonome, donc rien d'autre n'en dépend.

Habituellement, la bibliothèque jQuery n'est pas un bon candidat pour async car d'autres scripts en dépendent et vous souhaitez installer des gestionnaires d'événements afin que votre page puisse commencer à répondre aux événements utilisateur et vous devrez peut-être exécuter du code d'initialisation basé sur jQuery pour établir l'état initial de la page. Il peut être utilisé en mode asynchrone, mais d'autres scripts devront être codés pour ne pas s'exécuter tant que jQuery n'est pas chargé.

jfriend00
la source
8
Defer doit les exécuter dans l'ordre, mais exécuter avant dom-contentloaded. Cela ne signifie-t-il pas que le mettre en tête serait plus rapide, car il peut commencer à les télécharger AVANT que le corps html ne soit analysé?
Kevin
9
Vous avez dit que mettre des scripts headdedans et les configurer deferne serait pas plus rapide que de les mettre avant </body>, mais d'après ce que j'ai lu, c'est incorrect. Pensez-y - si vous mettez les scripts dedans <head>, alors ils commenceront à télécharger immédiatement, alors que s'ils sont juste avant, </body>alors tous les autres éléments seront téléchargés en premier.
Nate
12
@Nate - Cela ne accélérera pas le chargement de votre document, ce qui est mon point. Vous avez raison, cela pourrait améliorer le chargement du script plus tôt, mais cela pourrait également ralentir le chargement du document et de son contenu, car vous utilisez une partie de votre bande passante et utilisez l'une des connexions limitées que le navigateur établira avec un serveur donné. chargez le script tout en essayant de charger votre contenu.
jfriend00
4
"Si votre deuxième script dépend du premier script ... alors vous ne pouvez pas les faire asynchroniser ou différer" - ce n'est pas vrai, avec le report ils s'exécutent dans l'ordre.
DisgruntledGoat
2
À ce stade, l'exigence </body> n'est pas vraiment nécessaire avec les développements de navigateur depuis 2012, lorsque cette réponse a été publiée.
bgcode
845

Cette image explique la balise de script normale, l'async et le report

entrez la description de l'image ici

  • Les scripts asynchrones sont exécutés dès que le script est chargé, il ne garantit donc pas l'ordre d'exécution (un script que vous avez inclus à la fin peut s'exécuter avant le premier fichier de script)

  • Defer les scripts garantit l'ordre d'exécution dans lequel ils apparaissent dans la page.

Ref ce lien: http://www.growingwiththeweb.com/2014/02/async-vs-defer-attributes.html

Prasanth Bendra
la source
Je pense qu'un exemple avec plusieurs scripts aurait été mieux pour illustrer leur séquence
vsync
4
@writofmandamus On dirait que ça asyncva gagner. Voir stackoverflow.com/questions/13821151/…
Monsignor
Merci pour la bonne explication. Cependant, les images ne sont pas à l'échelle. Dans le cas de la seule <script>balise, la durée totale de chargement de la page est plus longue au moment du téléchargement du fichier de script.
arni
@BhavikHirani Selon ce site , utiliser à la fois async et defer dans la même balise de script utilise async si le navigateur le prend en charge, ou revient à différer s'il ne prend pas en charge async, mais prend en charge defer. Les comportements sont assez différents, donc je ne conseillerais pas d'utiliser les deux, car le résultat est imprévisible et peut être une excellente source de bugs.
Adrian Wiik
@arni Uniquement si la bande passante est pleinement utilisée, ce qui est rarement le cas. Et les deux téléchargements partageraient la bande passante, pas un bloc. - De plus: ces images montrent l'analyse en vert, pas en téléchargement.
Robert Siemer
213

HTML5: async,defer

En HTML5, vous pouvez indiquer au navigateur quand exécuter votre code JavaScript. Il y a 3 possibilités:

<script       src="myscript.js"></script>

<script async src="myscript.js"></script>

<script defer src="myscript.js"></script>
  1. Sans asyncou defer, le navigateur exécutera votre script immédiatement, avant de rendre les éléments situés en dessous de votre balise de script.

  2. Avec async(asynchrone), le navigateur continuera de charger la page HTML et de la rendre pendant que le navigateur charge et exécute le script en même temps.

  3. Avec defer, le navigateur exécutera votre script lorsque la page aura terminé l'analyse. (pas besoin de terminer le téléchargement de tous les fichiers image. C'est bien.)

Dinesh
la source
Le modèle blogger.com est requis async=""avant de valider et d'enregistrer les modifications du modèle.
noobninja
1
Remarque: il n'y a aucune garantie que les scripts s'exécuteront dans l'ordre où ils sont spécifiés à l'aide d'Async. "Donc, si votre deuxième script dépend du premier script, évitez Async."
Faisal Naseer
2
async- Les scripts sont exécutés dès leur téléchargement, sans tenir compte de leur ordre dans le fichier HTML.
vsync
30

Les deux asyncet les deferscripts commencent à se télécharger immédiatement sans interrompre l'analyseur et les deux prennent en charge un onloadgestionnaire facultatif pour répondre au besoin commun d'effectuer l'initialisation qui dépend du script.

La différence entre asyncet est defercentrée sur l'exécution du script. Chaque asyncscript s'exécute à la première occasion après la fin du téléchargement et avant l'événement de chargement de la fenêtre. Cela signifie qu'il est possible (et probable) que les asyncscripts ne soient pas exécutés dans l'ordre dans lequel ils se produisent dans la page. Alors que les deferscripts, d'autre part, sont garantis pour être exécutés dans l'ordre où ils se produisent dans la page. Cette exécution commence une fois l'analyse terminée, mais avant l' DOMContentLoadedévénement du document .

Source & détails: ici .

Zameer Khan
la source
25

Face au même type de problème et maintenant clairement compris comment les deux fonctionneront.J'espère que ce lien de référence sera utile ...

Async

Lorsque vous ajoutez l'attribut async à votre balise de script, les événements suivants se produisent.

<script src="myfile1.js" async></script>
<script src="myfile2.js" async></script>
  1. Faites des demandes parallèles pour récupérer les fichiers.
  2. Continuez d'analyser le document comme s'il n'avait jamais été interrompu.
  3. Exécutez les scripts individuels au moment du téléchargement des fichiers.

Reporter

Defer est très similaire à async avec une différence majeure. Voici ce qui se passe lorsqu'un navigateur rencontre un script avec l'attribut defer.

<script src="myfile1.js" defer></script>
<script src="myfile2.js" defer></script>
  1. Faites des demandes parallèles pour récupérer les fichiers individuels.
  2. Continuez d'analyser le document comme s'il n'avait jamais été interrompu.
  3. Terminez l'analyse du document même si les fichiers de script ont été téléchargés.
  4. Exécutez chaque script dans l'ordre où ils ont été rencontrés dans le document.

Référence: Différence entre Async et Defer

kamesh
la source
7

asyncet defertéléchargera le fichier pendant l'analyse HTML. Les deux n'interrompent pas l'analyseur.

  • Le script avec asyncattribut sera exécuté une fois téléchargé. Alors que le script avec deferattribut sera exécuté après avoir terminé l'analyse DOM.

  • Les scripts chargés avec asyncne garantissent aucune commande. Alors que les scripts chargés avec l' deferattribut conservent l'ordre dans lequel ils apparaissent sur le DOM.

À utiliser <script async>lorsque le script ne repose sur rien. quand le script dépend, utilisez.

La meilleure solution serait d'ajouter le au bas du corps. Il n'y aura aucun problème de blocage ou de rendu.

NavyaKumar
la source
Je veux juste apporter quelques précisions ici, deux choses se produisent ici 1. Téléchargement de la ressource 2. Exécution de la ressource. Le téléchargement de ressources dans les deux cas (async et defer) ne sont pas bloquants, cela signifie qu'ils ne bloquent pas l'analyse de html, tandis que l'exécution en async bloque l'analyse et en cas de report, l'exécution a lieu après l'analyse du balisage html, donc non bloquant dans ce cas.
pOoOf du
5

Je pense que Jake Archibald nous a présenté quelques idées en 2013 qui pourraient ajouter encore plus de positivité au sujet:

https://www.html5rocks.com/en/tutorials/speed/script-loading/

Le Saint Graal a un ensemble de scripts téléchargés immédiatement sans bloquer le rendu et exécutés dès que possible dans l'ordre où ils ont été ajoutés. Malheureusement, HTML vous déteste et ne vous laissera pas faire ça.

(...)

La réponse se trouve en fait dans la spécification HTML5, bien qu'elle soit cachée au bas de la section de chargement de script. " L'attribut async IDL contrôle si l'élément s'exécutera de manière asynchrone ou non. Si l'indicateur" force-async "de l'élément est défini, puis, lors de l'obtention, l'attribut async IDL doit renvoyer true, et lors de la définition, le" force-async " le drapeau doit d'abord être désactivé… ".

(...)

Les scripts qui sont créés dynamiquement et ajoutés au document sont asynchrones par défaut , ils ne bloquent pas le rendu et ne s'exécutent pas dès leur téléchargement, ce qui signifie qu'ils peuvent sortir dans le mauvais ordre. Cependant, nous pouvons explicitement les marquer comme non asynchrones:

[
    '//other-domain.com/1.js',
    '2.js'
].forEach(function(src) {
    var script = document.createElement('script');
    script.src = src;
    script.async = false;
    document.head.appendChild(script);
});

Cela donne à nos scripts un mélange de comportements qui ne peut pas être obtenu avec du HTML simple. En n'étant explicitement pas asynchrone, les scripts sont ajoutés à une file d'attente d'exécution, la même file d'attente à laquelle ils sont ajoutés dans notre premier exemple HTML brut. Cependant, en étant créés dynamiquement, ils sont exécutés en dehors de l'analyse de documents, donc le rendu n'est pas bloqué pendant le téléchargement (ne confondez pas le chargement de script non asynchrone avec la synchronisation XHR, ce qui n'est jamais une bonne chose).

Le script ci-dessus doit être inclus en ligne dans le haut des pages, mettre en file d'attente les téléchargements de script dès que possible sans perturber le rendu progressif, et s'exécute dès que possible dans l'ordre que vous avez spécifié. "2.js" est téléchargeable gratuitement avant "1.js", mais il ne sera pas exécuté tant que "1.js" n'aura pas été téléchargé et exécuté avec succès, ou ne le fera pas non plus. Hourra! téléchargement asynchrone mais exécution ordonnée !

Pourtant, ce n'est peut-être pas le moyen le plus rapide de charger des scripts:

(...) Avec l'exemple ci-dessus, le navigateur doit analyser et exécuter un script pour découvrir quels scripts télécharger. Cela cache vos scripts des scanners de préchargement. Les navigateurs utilisent ces scanners pour découvrir des ressources sur les pages que vous visiterez probablement la prochaine fois, ou découvrir des ressources de page pendant que l'analyseur est bloqué par une autre ressource.

Nous pouvons ajouter de la découvrabilité en mettant ceci en tête du document:

<link rel="subresource" href="//other-domain.com/1.js">
<link rel="subresource" href="2.js">

Cela indique au navigateur que la page a besoin de 1.js et 2.js. link [rel = subresource] est similaire à link [rel = prefetch], mais avec une sémantique différente. Malheureusement, il n'est actuellement pris en charge que dans Chrome, et vous devez déclarer les scripts à charger deux fois, une fois via les éléments de lien, puis à nouveau dans votre script.

Correction: à l' origine, j'avais déclaré que ceux-ci avaient été récupérés par le scanner de précharge, ils ne le sont pas, ils sont récupérés par l'analyseur ordinaire. Cependant, le scanner de préchargement pourrait les récupérer, ce n'est pas encore le cas, alors que les scripts inclus par le code exécutable ne peuvent jamais être préchargés. Merci à Yoav Weiss qui m'a corrigé dans les commentaires.

mjfneto
la source
1

Il semble que le comportement de différer et async dépend du navigateur, au moins sur la phase d'exécution. REMARQUE, le report s'applique uniquement aux scripts externes. Je suppose que l'async suit le même schéma.

Dans IE 11 et versions antérieures, l'ordre semble être le suivant:

  • async (pourrait s'exécuter partiellement pendant le chargement de la page)
  • aucun (pourrait s'exécuter pendant le chargement de la page)
  • différer (s'exécute après le chargement de la page, tout différer par ordre de placement dans le fichier)

Dans Edge, Webkit, etc., l'attribut async semble être ignoré ou placé à la fin:

  • data-pagespeed-no-defer (s'exécute avant tout autre script, pendant le chargement de la page)
  • aucun (pourrait s'exécuter pendant le chargement de la page)
  • différer (attend que DOM soit chargé, tout différer par ordre de placement dans le fichier)
  • async (semble attendre que DOM soit chargé)

Dans les navigateurs plus récents, l'attribut data-pagespeed-no-defer s'exécute avant tout autre script externe. C'est pour les scripts qui ne dépendent pas du DOM.

REMARQUE: utilisez defer lorsque vous avez besoin d'un ordre d'exécution explicite de vos scripts externes. Cela indique au navigateur d'exécuter tous les scripts différés par ordre de placement dans le fichier.

HORS: La taille des javascripts externes importait lors du chargement ... mais n'avait aucun effet sur l'ordre d'exécution.

Si vous êtes préoccupé par les performances de vos scripts, vous voudrez peut-être envisager la minification ou simplement les charger dynamiquement avec un XMLHttpRequest.

Charles Owen
la source
data-pagespeed-no-deferest un attribut utilisé par le module PageSpeed côté serveur . L' attribut par lui-même n'a aucun effet sur aucun navigateur. data-pagespeed-no-defer
Qtax