Остановить IE дважды загружать динамически включенный скрипт - PullRequest
11 голосов
/ 02 ноября 2009

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

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

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

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

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

Ответы [ 6 ]

15 голосов
/ 02 ноября 2009

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

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

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

Лучше всего избегать использования 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 на основе HTML-строк в jQuery для чего-либо вообще. Предполагается, что это исправит браузер ошибки, но обработка dumb-regex, по-моему, может вызвать столько же проблем, сколько и решить.)

Между прочим, при этом начальном вызове:

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

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

document.write('\x3Cscript src="js_test1.js" type="text/javascript">\x3C/script>"));
4 голосов
/ 02 ноября 2009

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

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

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

2 голосов
/ 02 ноября 2009

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

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

1 голос
/ 08 июня 2012

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

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

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

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

1 голос
/ 02 ноября 2009

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

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
}
0 голосов
/ 02 ноября 2009

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

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