36 votes

Ordre d'exécution du document.write Inline script de JavaScript

J'ai le script suivant, où le premier et le troisième document.writeline sont statiques et le second est généré :

<script language="javascript" type="text/javascript">
document.write("<script language='javascript' type='text/javascript' src='before.js'><\/sc" + "ript>");
document.write("<script language='javascript' type='text/javascript'>alert('during');<\/sc" + "ript>");
document.write("<script language='javascript' type='text/javascript' src='after.js'><\/sc" + "ript>");
</script>

Firefox et Chrome afficheront avant , pendant et après alors qu'Internet Explorer affiche d'abord pendant et c'est seulement à ce moment-là que l'on voit avant et après .

Je suis tombé sur un article qui dit que je ne suis pas le premier à rencontrer ça, mais ça ne me rassure pas.

Quelqu'un sait-il comment faire en sorte que l'ordre soit déterministe dans tous les navigateurs, ou comment modifier IE pour qu'il fonctionne comme tous les autres navigateurs sains d'esprit ?

Mises en garde : L'extrait de code est un reproducteur très simple. Il est généré sur le serveur et la deuxième script est la seule chose qui change. C'est un long script et la raison pour laquelle il y a deux scripts avant et après est que le navigateur les mettra en cache et que la partie dynamique du code sera aussi petite que possible. Il peut également apparaître plusieurs fois dans la même page avec un code généré différent.

24voto

Non, c'est le comportement d'Internet Explorer.

Si vous joignez des scripts de manière dynamique, IE, Firefox et Chrome téléchargeront tous les scripts de manière asynchrone.

Firefox et Chrome attendent le retour de toutes les requêtes asynchrones et exécutent ensuite les scripts dans l'ordre où ils sont attachés dans le DOM, mais IE exécute les scripts dans l'ordre où ils sont renvoyés par le fil.

Comme l'alerte prend moins de temps à "récupérer" qu'un fichier javascript externe, cela explique probablement le comportement que vous observez.

D'après l'article de Kristoffer Henriksson post sur le sujet du chargement asynchrone des script. :

Dans ce scénario, IE et Firefox vont téléchargeront les deux scripts mais Internet Explorer les exécutera également dans la fenêtre l'ordre dans lequel ils ont été téléchargés tandis que Firefox les télécharge de manière asynchrone mais les exécute toujours dans l'ordre où ils sont attachés dans le DOM.

Dans Internet Explorer, cela signifie que vos scripts ne peuvent pas dépendre les uns des autres l'un de l'autre, car l'ordre d'exécution d'exécution variera en fonction du trafic du réseau, des caches, etc.

Envisagez d'utiliser un chargeur Javascript. Il vous permettra de spécifier les dépendances de script et l'ordre d'exécution tout en chargeant vos scripts de manière asynchrone pour plus de rapidité ainsi que pour lisser certaines différences entre les navigateurs.

Voici un bon aperçu de quelques-unes d'entre elles : Essential JavaScript : les cinq principaux chargeurs de script .

J'ai utilisé à la fois RequireJS et LabJS. À mon avis, LabJS est un peu moins opiniâtre.

5voto

Omer van Kloeten Points 6268

J'ai trouvé une réponse plus à mon goût :

<script language="javascript" type="text/javascript">
document.write("<script language='javascript' type='text/javascript' src='before.js'><\/sc" + "ript>");
document.write("<script defer language='javascript' type='text/javascript'>alert('during');<\/sc" + "ript>");
document.write("<script defer language='javascript' type='text/javascript' src='after.js'><\/sc" + "ript>");
</script>

Cela permettra de différer le chargement des deux pendant et après jusqu'à ce que la page ait fini de se charger.

Je pense que c'est le mieux que je puisse faire. J'espère que quelqu'un sera en mesure de donner une meilleure réponse.

1voto

Prestaul Points 31986

Diapositives 25/26 de cette présentation parlent des caractéristiques des différentes méthodes d'insertion de scripts. Il suggère qu'IE est le seul navigateur qui exécutera ces scripts dans l'ordre. Tous les autres navigateurs les exécuteront dans l'ordre de leur chargement. Même IE ne les exécutera pas dans l'ordre si un ou plusieurs d'entre eux ont des js en ligne au lieu d'un src.

L'une des méthodes proposées consiste à insérer un nouvel élément DOM :

var se1 = document.createElement('script');
se1.src = 'a.js';

var se2 = document.createElement('script');
se2.src = 'b.js';

var se3 = document.createElement('script');
se3.src = 'c.js';

var head = document.getElementsByTagName('head')[0]
head.appendChild(se1);
head.appendChild(se2);
head.appendChild(se3);

Pour que la deuxième section script soit générée, vous pourriez utiliser un script pour générer ce contenu et passer les paramètres :

se2.src = 'generateScript.php?params=' + someParam;

EDIT : En dépit de ce que dit l'article que j'ai cité, mes tests suggèrent que la plupart des navigateurs exécuteront vos scripts document.write dans l'ordre s'ils ont chacun un src, donc même si je pense que la méthode ci-dessus est préférable, vous pouvez aussi faire cela :

<script language="javascript" type="text/javascript">
document.write("<script type='text/javascript' src='before.js'><\/sc" + "ript>");
document.write("<script type='text/javascript' src='during.php?params=" + params + "'><\/sc" + "ript>");
document.write("<script type='text/javascript' src='after.js'><\/sc" + "ript>");
</script>

EDITER A NOUVEAU (réponse aux commentaires à moi-même et à d'autres) : Vous générez déjà le script sur votre page. Tout ce que vous faites peut être déplacé vers un autre script côté serveur qui génère le même bloc de code. Si vous avez besoin de paramètres sur votre page, passez-les au script dans la chaîne de requête.

Vous pouvez également utiliser cette même méthode si, comme vous le suggérez, vous générez le script en ligne plusieurs fois :

<script language="javascript" type="text/javascript">
document.write("<script type='text/javascript' src='before.js'><\/sc" + "ript>");
document.write("<script type='text/javascript' src='during.php?params=" + params1 + "'><\/sc" + "ript>");
document.write("<script type='text/javascript' src='during.php?params=" + params2 + "'><\/sc" + "ript>");
document.write("<script type='text/javascript' src='during.php?params=" + params3 + "'><\/sc" + "ript>");
document.write("<script type='text/javascript' src='after.js'><\/sc" + "ript>");
</script>

Cependant, il semble que vous abordiez la question de la mauvaise manière. Si vous générez un gros bloc de code plusieurs fois, vous devriez probablement le remplacer par une seule fonction js et l'appeler avec différents paramètres...

1voto

Dustman Points 1706

Ok... pendant...

// During.js
during[fish]();

après...

// After.js
alert("After");
fish++

HTML

<!-- some html -->
<script language="javascript" type="text/javascript">
document.write("<script language='javascript' type='text/javascript' src='before.js'></sc" + "ript>");
document.write("<script language='javascript' type='text/javascript'>during[" + fish + "] = function(){alert('During!' + fish);}</sc" + "ript>");
document.write("<script language='javascript' type='text/javascript' src='during.js'></sc" + "ript>");
document.write("<script language='javascript' type='text/javascript' src='after.js'></sc" + "ript>");
</script>
<!-- some other html -->
<script language="javascript" type="text/javascript">
document.write("<script language='javascript' type='text/javascript' src='before.js'></sc" + "ript>");
document.write("<script language='javascript' type='text/javascript'>during[" + fish + "] = function(){alert('During!' + fish);}</sc" + "ript>");
document.write("<script language='javascript' type='text/javascript' src='during.js'></sc" + "ript>");
document.write("<script language='javascript' type='text/javascript' src='after.js'></sc" + "ript>");
</script>

Je suis enclin à être d'accord sur la façon dont ça commence à sentir, cependant. En particulier, pourquoi ne pas coder le "pendant" dans un fichier js créé dynamiquement, et l'insérer ?

Notez que le script généré dynamiquement va à l'intérieur de la fonction dans le deuxième document.write.
Testé dans FF2, IE7

1voto

Victor Points 3774

Vous pouvez forcer l'exécution sécurisée en définissant des événements "onload" (ou similaires) sur les scripts et en injectant le prochain événement dans la fonction d'événement. Ce n'est pas trivial, mais il existe de nombreux exemples, en voici un.

http://www.phpied.com/javascript-include-ready-onload/

Je pense que des bibliothèques populaires comme jQuery ou prototype peuvent vous aider dans ce domaine.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X