Подтвердить что ты не робот

JavaScript document.write Inline Script Порядок выполнения

У меня есть следующий script, где первый и третий 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 для работы, как и все другие, разумные браузеры?

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

4b9b3361

Ответ 1

Я нашел ответ больше по своему вкусу:

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

Это отложит загрузку как во время, так и после, пока страница не закончит загрузку.

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

Ответ 2

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

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

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

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

От Kristoffer Henriksson сообщение о теме асинхронного script загрузки:

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

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

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

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

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

Ответ 3

Слайды 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);

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

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 на своей странице. Все, что вы делаете, можно перенести на другую серверную часть script, которая генерирует тот же блок кода. Если вам нужны параметры на вашей странице, передайте их в script в строке запроса.

Кроме того, вы можете использовать этот же метод, если, как вы полагаете, вы создаете встроенный 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-функцией и называть ее разными параметрами...

Ответ 4

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

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

Я склонен согласиться с тем, как это начинает пахнуть. В частности, почему вы не могли кодировать "во время" в динамически созданный js файл и вставить это?

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

Ответ 5

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

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

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

Ответ 6

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

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

В before.js:

alert("Before");
callGeneratedContent();

В after.js:

alert("After");

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

Ответ 7

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

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