Остановить 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
?