2009-11-02 14 views
11

Estoy incluyendo contenido relacionado en misc. páginas web agregando una etiqueta <script> cerca del final de la etiqueta <body>, que luego carga otros archivos javascript. El flujo es un poco complicado, así que voy a tratar de explicarlo antes de pedir a mi pregunta:Detener IE cargar secuencia de comandos incluida dinámicamente dos veces

  • Un navegador carga una página con nuestro elemento <script> cerca del extremo del elemento <body>
  • el atributo src de la la etiqueta de script apunta a un archivo javascript que (en algunos casos) inyecta un segundo elemento <script>
  • El atributo src del elemento <script> inyectado apunta a otro archivo javascript, que finalmente inyecta algún contenido en la parte apropiada de la página.

Estamos utilizando este enfoque de dos etapas para poder hacer algo de procesamiento básico antes de decidir si se debe incluir el contenido final, que podría tomar algún tiempo para cargar.

El problema es que IE8 (y quizás versiones anteriores) carga el último javascript dos veces. Parece que el acto de establecer el atributo src desencadenará una carga, pero también se agregará la etiqueta de script al DOM. Hay alguna manera de evitar esto?

He creado un bare-bones demo del problema. Si tiene alguna forma de rastrear las solicitudes HTTP, verá que IE8 carga js_test2.js dos veces.

Respuesta

15

La diferencia raíz es que IE ejecuta un elemento de guión la primera vez que se añade a childNodes de un elemento padre, independientemente de si el elemento principal está realmente en el documento. Otros navegadores solo ejecutan script cuando se agrega a un nodo dentro del árbol de childNodes del documento.

de domManip función (línea 524 de jQuery 1.3.2), la cual es invocado append y otros métodos similares jQuery, trata de ser inteligente y pide evalScript para cualquier <script> elementos que encuentra en la final HTML analizada, para ejecutar el jQuery secuencia de comandos (al realizar solicitudes AJAX si es necesario para scripts externos). (Los elementos reales del script se han eliminado de los childNodes analizados para evitar que se ejecuten al insertarlos en el documento, presumiblemente para que los scripts solo se ejecuten una vez cuando el contenido que los contiene se agregue a varios elementos a la vez).)

Sin embargo, debido a que la función clean anterior, al analizar el código HTML, anexó el elemento script a un div envoltorio, IE ya habrá ejecutado el script. Entonces tienes dos ejecuciones.

Lo mejor que se puede hacer es evitar el uso de las funciones domManip como append con cadenas HTML cuando se está haciendo algo con las secuencias de comandos.

De hecho, olvídate de poner tu contenido en una cadena HTML serializada y obtener jQuery para analizarlo; sólo lo hacen el más fiable sin formato DOM manera:

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

(Para ser honesto, después de ver el código fuente que revuelve el estómago de la función clean, basada en HTML cuerdas estoy teniendo serias dudas sobre el uso de jQuery . manipulaciones de DOM para nada en absoluto que se supone que arreglar los errores del navegador, pero el procesamiento mudo en expresiones regulares me parece probable que cause tantos problemas como los que resuelve)

cierto con esta llamada inicial:.

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

No necesita deshacerse capa aquí; No sé por qué tanta gente lo hace. Debe evitarse la secuencia </ en un script en línea, ya que terminaría con la etiqueta <script>, y si está haciendo XHTML < y &, debe evitarse también (o ]]> si está usando un contenedor CDATA), pero hay una más fácil forma de hacer todo eso con sólo literales de cadena de JavaScript:

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

Gracias por esta respuesta muy completa. De hecho, he vuelto a la manera DOM más tradicional, y funciona bien ahora. En cuanto a la separación de la llamada inicial: si recuerdo correctamente copié el código que Google Analytics usa para incluir su script, bajo la suposición (quizás falsa) de que si alguien sabe cómo incluir sólidamente un javascript remoto, es la gente de GA . Gracias por la aclaración. – stiang

2

Parecería que jquery está obteniendo la segunda instancia de js_test2 usando XmlHttpRequest.

Por qué no lo sé, pero es el comportamiento de JQuery lo que necesita para investigar.

+0

Eso es muy extraño, pero parece que tiene razón. Si utilizo appendChild en lugar de append de jQuery, no carga js_test2.js dos veces. Supongo que si hubiera hecho la demo/really/bare-bones (sin jQuery), lo habría descubierto yo mismo. ¡Gracias! – stiang

+0

He hecho una investigación. Los resultados (a continuación) no son agradables. – bobince

4

He visto ese comportamiento en otras versiones de IE en circunstancias similares (como la clonación de nodos <script>) y nunca llegué a saber cómo evitar que el script se ejecute dos veces, entonces lo que terminé haciendo fue agregar un guardián en el código del script para que no se ejecute dos veces. Era algo así como:

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

Si no puede encontrar una manera de evitar que el script se ejecute dos veces, es posible que desee probar este enfoque en su lugar.

+0

impresionante, estaba tratando de encontrar una forma de comprobar si se definía una variable global, sin por supuesto definirla como falsa antes de ejecutar el script. ¡Gracias! –

1

Usted puede comprobar para ver si un guión ya está en el documento antes de cargar IT

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

es posible que esto se debe a que utiliza document.write cuando ya estás en un elemento de <script>. ¿Has intentado anexar a <head> en lugar de document.write?

1

Encuentro el mismo problema, solo sucede en IE.

html() cadenas método de jQuery es: html>append>domManip>clean

clean() método de usar innerHTML cadena de cosméticos a la DOM, innerHTML en IE tiene un error que script etiqueta se carga de inmediato (primera carga), jQuery evalScript etiquetas script en el extremo del método domManip (carga ajax). Luego, el archivo de script carga dos veces en IE.

creo jQuery debería solucionar este problema, actualice el método clean()

Cuestiones relacionadas