Остановить IE от загрузки динамически включенного script дважды

Я включаю некоторые связанные материалы по разным. веб-страниц, добавив тег <script> рядом с тегом <body>, который затем загружает другие файлы javascript. Поток немного запутан, поэтому я стараюсь объяснить его, прежде чем задавать свой вопрос:

  • Браузер загружает страницу с помощью нашего элемента <script> в конце элемента <body>
  • Атрибут src тега script указывает на файл javascript, который (в некоторых случаях) вставляет второй элемент <script>
  • Атрибут src введенного элемента <script> указывает на еще один файл javascript, который, наконец, вводит некоторый контент в соответствующую часть страницы.

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

Проблема в том, что IE8 (и, возможно, более старые версии) загружает последний javascript дважды. Похоже, что действие установки атрибута src приведет к загрузке, но добавит тег script в DOM. Есть ли способ избежать этого?

Я создал демонстрацию голой кости проблемы. Если у вас есть какой-то способ отслеживания HTTP-запросов, вы увидите, что IE8 загружает js_test2.js дважды.

Ответ 1

Коренное различие заключается в том, что IE выполняет элемент script при первом добавлении к родительскому элементу childNodes, независимо от того, действительно ли родительский элемент находится в документе. Другие браузеры выполняют script, когда они добавляются в node внутри дерева документов childNodes.

Функция

jQuery domManip (строка 524 из jQuery 1.3.2), которая вызывается append и другими подобными методами jQuery, пытается быть умной и вызывает evalScript для любых элементов <script>, которые она находит в окончательный проанализированный HTML, для выполнения script (путем выполнения AJAX-запросов, если это необходимо для внешних скриптов). (Фактические элементы script были удалены из проанализированных childNodes, чтобы остановить их выполнение при вставке в документ, предположительно, чтобы сценарии выполнялись только один раз, когда содержимое, содержащее их, было добавлено сразу к нескольким элементам.)

Однако, поскольку предыдущая функция clean при анализе HTML добавила элемент script в div оболочки, IE уже выполнит script. Итак, вы получаете два исполнения.

Лучше всего избегать использования domManip функций типа append со строками HTML, когда вы делаете что-либо со сценариями.

Фактически, забудьте поместить свой контент в сериализованную строку HTML и получить jQuery для его анализа; просто сделайте это гораздо более надежным способом DOM:

var s= document.createElement('script');
s.type= 'text/javascript';
s.charset= 'UTF-8';
s.src= 'js_test2.js';
document.getElementById('some_container').appendChild(s);

(Честно говоря, после просмотра исходного кода, вызванного желудком, функции clean, у меня возникли серьезные сомнения по поводу использования DOM-манипуляций на основе jQuery HTML-string для чего-либо вообще. Предполагается исправить браузер ошибок, но обработка немого-регулярного выражения, по-видимому, мне может вызвать столько проблем, сколько она решает.)

Кстати, с этим начальным вызовом:

document.write(unescape("%3Cscript src='js_test1.js' type='text/javascript'%3E%3C/script%3E"));

Здесь вам не нужно unescape; Я не знаю, почему так много людей. Последовательность </ следует избегать во встроенном script, так как это приведет к тегу <script>, и если вы делаете XHTML < и & тоже следует избегать (или ]]>, если вы "используя обертку CDATA" ), но есть более простой способ сделать все это с помощью только строковых литералов JavaScript:

document.write('\x3Cscript src="js_test1.js" type="text/javascript">\x3C/script>"));

Ответ 2

Я видел, что такое поведение происходит в других версиях IE при подобных обстоятельствах (например, клонирование узлов <script>), и я никогда не знал, как остановить выполнение script от выполнения дважды, так что я оказался делая добавление охранника в код script, чтобы он не запускался дважды. Это было что-то вроде:

if (typeof(loaded) == 'undefined') {
    // the whole code goes in here
    var loaded = true;
}

Если вы не можете найти способ предотвратить выполнение script дважды, вы можете попробовать вместо этого.

Ответ 3

Казалось бы, jquery извлекает второй экземпляр js_test2 с помощью XmlHttpRequest.

Почему я не знаю, но это поведение JQuery, которое вам нужно исследовать.

Ответ 4

Вы можете проверить, есть ли script в документе перед загрузкой -

function fetchscript(url, callback){
 var S= document.getElementsByTagName('script'), L= S.length;
 while(L){
  if(S[--L].src== url) return true;
 }
 //create and append script and any callbacks
}

Ответ 5

Я нахожу ту же проблему, только в IE.

Цепочки методов html() jQuery: html>append>domManip>clean

clean() использовать метод innerHTML сделать строку в DOM, innerHTML в IE есть ошибка, в которой тег script будет немедленно загружать (первая загрузка), теги jQuery evalScript script в конце domManip (ajax load). then script загрузка файла дважды в IE.

Я думаю, что jQuery должен исправить эту проблему, обновить метод clean()

Ответ 6

Возможно, это связано с тем, что вы используете document.write, когда вы уже находитесь в элементе <script>. Вы пытались добавить к <head> вместо document.write?