Charger et exécuter l'ordre des scripts

Il existe tellement de façons différentes d'inclure JavaScript dans une page html. Je connais les options suivantes:

  • Code en ligne ou chargé à partir d'URI externe
  • Inclus dans la balise <head> ou <body> [ 1 , 2 ]
  • N'ayant aucun attribut de defer ou async (uniquement des scripts externes)
  • Inclus dans la source statique ou ajouté dynamiquement par d'autres scripts (à différents états d'analyse, avec différentes méthodes)

Sans compter les scripts du disque dur, javascript: URIs et onEvent -attributes [ 3 ], il existe déjà 16 alternatives pour exécuter JS et je suis sûr d'avoir oublié quelque chose.

Je ne suis pas tellement préoccupé par le chargement rapide (parallèle), je suis plus curieux de l'ordre d'exécution (qui peut dépendre de l'ordre de chargement et de l' ordre des documents ). Existe-t-il une bonne référence (cross-browser) qui couvre vraiment tous les cas? Par exemple, http://www.websiteoptimization.com/speed/tweak/defer/ ne concerne que 6, et teste surtout les anciens navigateurs.

Comme je le crains il n'y a pas, voici ma question spécifique: j'ai des scripts de tête (externes) pour l'initialisation et le chargement de script. Ensuite, j'ai deux scripts statiques en ligne à la fin du corps. Le premier permet au chargeur de script d'ajouter dynamiquement un autre élément de script (référant js externe) au corps. La seconde des scripts statiques en ligne veut utiliser js à partir du script externe ajouté. Peut-il compter sur l'autre ayant été exécuté (et pourquoi :-)?

Si vous ne chargez pas dynamiquement les scripts ou que vous les qualifiez de différé ou d'asynchrone, les scripts sont chargés dans l'ordre rencontré dans la page. Peu importe s'il s'agit d'un script externe ou d'un script en ligne – ils sont exécutés dans l'ordre dans lequel ils se trouvent dans la page. Les scripts en ligne qui suivent les scripts externes ont lieu jusqu'à ce que tous les scripts externes qui sont venus avant ils ont été chargés et exécutés.

Les scripts asynchrones (indépendamment de la manière dont ils sont spécifiés comme asynchrones) sont chargés et exécutés dans un ordre imprévisible. Le navigateur les charge en parallèle et il est libre de les exécuter dans n'importe quel ordre qu'il veut.

Il n'y a pas d'ordre prévisible parmi les choses asynchrones multiples. Si l'on avait besoin d'un ordre prévisible, il faudrait le coder en vous enregistrant pour les notifications de chargement à partir des scripts asynchrones et des appels javascript par séquençage manuel lorsque les éléments appropriés sont chargés.

Lorsqu'une étiquette de script est insérée de manière dynamique, la manière dont l'ordre d'exécution se comporte dépendra du navigateur. Vous pouvez voir comment Firefox se comporte dans cet article de référence . En bref, les versions plus récentes de Firefox par défaut une balise de script ajoutée dynamiquement à asynchroniser à moins que la balise du script ait été définie autrement.

Une balise de script avec async peut être exécutée dès qu'elle est chargée. En fait, le navigateur peut interrompre l'analyseur de tout ce qu'il faisait et exécuter ce script. Donc, il peut vraiment fonctionner à tout moment. Si le script a été mis en cache, il pourrait être exécuté presque immédiatement. Si le script prend un certain temps à charger, il peut s'exécuter après l'analyse de l'analyseur. La seule chose à retenir avec async c'est qu'elle peut fonctionner n'importe quand et que ce temps n'est pas prévisible.

Une étiquette de script avec le defer attend jusqu'à ce que l'analyseur complet soit terminé et exécute tous les scripts marqués avec defer dans l'ordre où ils ont été rencontrés. Cela vous permet de marquer plusieurs scripts qui dépendent les uns des autres pour defer . Ils seront tous reportés jusqu'à la fin de l'analyse du document, mais ils seront exécutés dans l'ordre où ils se sont retrouvés en préservant leurs dépendances. Je pense à defer comme si les scripts sont déposés dans une file d'attente qui sera traitée après la fin de l'analyseur. Techniquement, le navigateur peut télécharger les scripts en arrière-plan à tout moment, mais ils ne vont pas exécuter ou bloquer l'analyseur jusqu'à ce que l'analyseur soit terminé en analysant la page et en analysant et en exécutant tous les scripts en ligne qui ne sont pas marqués de différer ou d'assynchroniser.

Voici un devis de cet article:

Les scripts insérés dans un script sont exécutés de manière asynchrone dans IE et WebKit, mais de manière synchrone dans Opera et Firefox pré-4.0.

La partie pertinente de la spécification HTML5 (pour les nouveaux navigateurs compatibles) est ici . Il y a beaucoup d'écriture sur le comportement asynchrone. De toute évidence, cette spécification ne s'applique pas aux navigateurs plus anciens (ou aux navigateurs mal confirmés) qui sont les comportements que vous devriez probablement tester pour déterminer.

Une citation de la spécification HTML5:

Ensuite, la première des options suivantes qui décrit la situation doit être suivie:

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-insert", et que l'élément n'a pas d'attribut asynch. L'élément doit être ajouté à la fin de la liste de Les scripts qui s'exécutent lorsque le document a terminé l'analyse associée au document de l'analyseur qui a créé l'élément.

La tâche que la source de la tâche réseau place sur la file d'attente des tâches une fois que l'algorithme de récupération est terminé doit définir le drapeau «prêt à être parser-exécuté» de l'élément. L'analyseur gère l'exécution du script.

Si l'élément a un attribut src et que l'élément a été marqué comme "parser-insert", et que l'élément n'a pas d'attribut asynch. L'élément est le script de blocage de l'analyse en attente du document de l'analyseur qui a créé l'élément. (Il ne peut y avoir qu'un tel script par document à la fois.)

La tâche que la source de la tâche réseau place sur la file d'attente des tâches une fois que l'algorithme de récupération est terminé doit définir le drapeau «prêt à être parser-exécuté» de l'élément. L'analyseur gère l'exécution du script.

Si l'élément n'a pas d'attribut src et que l'élément a été marqué comme "parser-insert", et que le document de l'analyseur HTML ou l'analyseur XML qui a créé l'élément script comporte une feuille de style bloquant les scripts. L'élément est le Script de blocage d'analyse en attente du Document de l'analyseur qui a créé l'élément. (Il ne peut y avoir qu'un tel script par document à la fois.)

Définissez le drapeau "prêt à être parser" de l'élément. L'analyseur gère l'exécution du script.

Si l'élément a un attribut src, n'a pas d'attribut asynchrone et n'a pas le symbole "forcé-async". L'élément doit être ajouté à la fin de la liste des scripts qui s'exécuteront dans l'ordre dès que possible associé Avec le document de l'élément de script au moment de la préparation d'un algorithme de script.

La tâche que la source de la tâche de réseau place sur la file d'attente des tâches une fois que l'algorithme de récupération est terminé doit exécuter les étapes suivantes:

Si l'élément n'est pas maintenant le premier élément de la liste des scripts qui s'exécutera dans l'ordre le plus tôt possible auquel il a été ajouté ci-dessus, marquer l'élément comme prêt mais annuler ces étapes sans exécuter le script.

Exécution: Exécutez le bloc de script correspondant au premier élément de script dans cette liste de scripts qui s'exécutera dans l'ordre le plus tôt possible.

Supprimez le premier élément de cette liste de scripts qui s'exécutera dans l'ordre le plus tôt possible.

Si cette liste de scripts qui s'exécute dans l'ordre le plus tôt possible n'est toujours pas vide et que la première entrée a déjà été marquée comme étant prête, revenez à l'étape marquée d'exécution.

Si l'élément a un attribut src L'élément doit être ajouté à l'ensemble des scripts qui s'exécuteront dès que possible du document de l'élément de script au moment de la préparation d'un algorithme de script.

La tâche que la source de la tâche réseau place sur la file d'attente des tâches une fois que l'algorithme de récupération est terminé doit exécuter le bloc de script et ensuite supprimer l'élément de l'ensemble de scripts qui s'exécutera le plus tôt possible.

Sinon, l'agent utilisateur doit exécuter immédiatement le bloc de script, même si d'autres scripts sont déjà en cours d'exécution.

Le navigateur exécutera les scripts dans l'ordre où il les trouve. Si vous appelez un script externe, cela bloquera la page jusqu'à ce que le script ait été chargé et exécuté.

Pour tester ce fait:

 // file: test.php sleep(10); die("alert('Done!');"); // HTML file: <script type="text/javascript" src="test.php"></script> 

Les scripts ajoutés dynamiquement sont exécutés dès qu'ils sont ajoutés au document.

Pour tester ce fait:

 <!DOCTYPE HTML> <html> <head> <title>Test</title> </head> <body> <script type="text/javascript"> var s = document.createElement('script'); s.type = "text/javascript"; s.src = "link.js"; // file contains alert("hello!"); document.body.appendChild(s); alert("appended"); </script> <script type="text/javascript"> alert("final"); </script> </body> </html> 

L'ordre des alertes est "ajouté" -> "bonjour!" -> "final"

Si dans un script vous tentez d'accéder à un élément qui n'a pas encore été atteint (exemple: <script>do something with #blah</script><div id="blah"></div> ), vous obtiendrez un Erreur.

Dans l'ensemble, oui, vous pouvez inclure des scripts externes, puis accéder à leurs fonctions et variables, mais seulement si vous quittez la <script> et commencez une nouvelle.

 var scriptMap =["scriptUrl1","scriptUrl2", "scriptUrl3"]; var order = 0; function loadScriptInOrder(){ if(order == scriptMap.length) { return; } var JSLink = scriptMap[order]; var JSElement = document.createElement('script'); JSElement.src = JSLink; JSElement.onload = callback; document.getElementsByTagName('body')[0].appendChild(JSElement); function callback(){ order++; loadScriptInOrder(); } }; loadScriptInOrder();