JavaScript document.write Порядок выполнения встроенных скриптов - PullRequest
36 голосов
/ 18 сентября 2008

У меня есть следующий скрипт, где первый и третий document.writeline являются статическими, а второй генерируется :

<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 и Chrome будут отображать до , во время и после , в то время как Internet Explorer сначала показывает во время и только после этого показывает до и после .

Я натолкнулся на статью, в которой говорится , что я не первый, кто сталкивался с этим, но вряд ли заставляет меня чувствовать себя лучше.

Кто-нибудь знает, как я могу установить порядок, чтобы быть детерминированным во всех браузерах, или взломать IE, чтобы работать как все другие, нормальные браузеры?

Предостережения : Фрагмент кода - очень простое воспроизведение. Он генерируется на сервере, и второй скрипт - это единственное, что меняется. Это длинный сценарий, и причина в том, что до и после него есть два сценария, так что браузер будет их кэшировать, а динамическая часть кода будет как можно меньше. Он также может появляться много раз на одной странице с другим сгенерированным кодом.

Ответы [ 7 ]

24 голосов
/ 18 сентября 2008

Нет, это поведение Internet Explorer.

Если вы присоединяете сценарии динамически, IE, Firefox и Chrome будут загружать сценарии асинхронно.

Firefox и Chrome будут ждать, пока все асинхронные запросы не вернутся, а затем выполнят сценарии в порядке их подключения в DOM, но IE выполнит сценарии в том порядке, в котором они возвращены по проводам.

Поскольку для извлечения оповещения требуется меньше времени, чем для внешнего файла javascript, это, вероятно, объясняет поведение, которое вы видите.

Из сообщения Кристоффера Хенрикссона на тему асинхронной загрузки скриптов :

В этом сценарии IE и Firefox будут скачать оба скрипта но интернет Explorer также выполнит их в Порядок они заканчивают загрузку в тогда как Firefox скачивает их асинхронно, но все еще выполняет их в порядке их добавления в DOM.

В Internet Explorer это означает, что ваш сценарии не могут зависеть от друг друга как порядок исполнения будет варьироваться в зависимости от сети трафик, кэши и т. д.

Рассмотрите возможность использования загрузчика Javascript. Это позволит вам указать зависимости скриптов и порядок их выполнения, а также асинхронно загружать ваши скрипты для скорости и сгладить некоторые различия в браузере.

Это довольно хороший обзор некоторых из них: Основной JavaScript: пять лучших загрузчиков скриптов .

Я использовал оба RequireJS и LabJS. На мой взгляд, LabJS чуть менее самоуверен.

5 голосов
/ 23 сентября 2008

Мне больше понравился ответ:

<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>

Это будет откладывать загрузку как во время , так и после , пока страница не загрузится.

Я думаю, это так хорошо, как я могу получить. Надеюсь, кто-нибудь сможет дать лучший ответ.

1 голос
/ 19 сентября 2008

Вы можете принудительно выполнить последовательное выполнение, определив события «onload» (или аналогичные) в сценариях и добавив следующее в функцию события. Это не тривиально, но есть множество примеров, вот один.

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

Я думаю, что популярные библиотеки, такие как jQuery или прототип, могут помочь с этим.

1 голос
/ 18 сентября 2008

Хорошо ... во время ...

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

после ...

// 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>

Хотя я склонен согласиться с тем, как это пахнет. В частности, почему вы не можете сгенерировать «while» в динамически создаваемый js-файл и вставить его?

Обратите внимание, что динамически генерируемый скрипт помещается в функцию во second document.write.
Протестировано в FF2, IE7

1 голос
/ 18 сентября 2008

Слайды 25/26 из этой презентации рассказывают о характеристиках различных методов вставки скриптов. Это говорит о том, что IE - единственный браузер, который будет выполнять эти скрипты по порядку. Все остальные браузеры будут выполнять их в том порядке, в котором они заканчивают загрузку. Даже IE не выполнит их по порядку, если у одного или нескольких встроенных js вместо src.

Один из предложенных методов - вставить новый элемент 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);

Чтобы создать второй раздел сценария, вы можете использовать сценарий для создания этого содержимого и передачи параметров:

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

РЕДАКТИРОВАТЬ: Несмотря на то, что в статье, которую я разместил, говорится, что мое тестирование показывает, что большинство браузеров будут выполнять ваши сценарии document.write в том случае, если у каждого из них есть src, поэтому, хотя я думаю, что приведенный выше метод предпочтительнее, вы могли бы сделать это также:

<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>

ВНОВЬ РЕДАКТИРОВАТЬ (ответ на комментарии к себе и другим): Вы уже генерируете скрипт на своей странице. Все, что вы делаете, может быть перенесено в другой серверный скрипт, который генерирует тот же блок кода. Если вам нужны параметры на вашей странице, то передайте их сценарию в строке запроса.

Кроме того, вы можете использовать этот же метод, если, как вы предлагаете, вы генерируете встроенный скрипт несколько раз:

<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>

Однако это начинает выглядеть так, как будто вы подходите к этому неверно. Если вы генерируете большой блок кода несколько раз, вам, вероятно, следует заменить его одной функцией js и вместо этого вызывать его с другими параметрами ...

0 голосов
/ 03 апреля 2009

Как насчет этого:

<script>
document.write("<script src='before.js'><\/script>");
</script>

<script >
document.write("<script>alert('during');<\/script>");
</script>

<script>
document.write("<script src='after.js'><\/script>");
</script>
0 голосов
/ 19 сентября 2008

Код для предоставления:

<script language="javascript" type="text/javascript">
document.write("<script language='javascript' type='text/javascript'>function callGeneratedContent() { alert('during'); }<\x2Fscript>");
document.write("<script language='javascript' type='text/javascript' src='before.js'><\x2Fscript>");
document.write("<script language='javascript' type='text/javascript' src='after.js'><\x2Fscript>");
</script>

In before.js:

alert("Before");
callGeneratedContent();

In after.js:

alert("After");

Вы должны поставить сгенерированную строку первой, иначе FF будет жаловаться, потому что она выполняется перед .js до просмотра определения функции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...