2009-08-28 10 views
12

Estoy escribiendo una aplicación web que tiene un "shell" externo estático y una sección de contenido dinámico. La sección de contenido dinámico tiene muchas actualizaciones a medida que los usuarios navegan por el sistema. Cuando se carga un nuevo bloque de contenido, también puede cargar opcionalmente otro archivo JavaScript. En nombre de una buena gestión interna, elimino los bloques de scripts del DOM que se aplican a los bloques de contenido antiguos, ya que ese JavaScript ya no es necesario.¿Se puede descargar JavaScript cargado dinámicamente?

El problema viene después, cuando me di cuenta de que, aunque eliminé el elemento <script> del DOM, el JavaScript que se evaluó anteriormente todavía está disponible para su ejecución. Eso tiene sentido, por supuesto, pero me preocupa que pueda causar una pérdida de memoria si los usuarios navegan a muchas secciones diferentes.

La pregunta entonces, ¿debería preocuparme esta situación? Si es así, ¿hay alguna manera de obligar al navegador a limpiar JavaScript obsoleto?

Respuesta

14

<theory> Puede ir con un enfoque más orientado a objetos, y construir el modelo de manera que cada bloque de bloques de javascript aparezca como sus propios objetos, con sus propios métodos. Al descargarlo, simplemente establece ese objeto en null. </theory>

3

Si guarda el código evaluado en espacios de nombres, tales como:

var MYAPP = { 
    myFunc: function(a) { ... } 
} 

"liberar" todo el asunto debe ser tan simple como la creación de MYPP a algún valor al azar, ala

MYAPP = 1 

Esto no depende de que no haya otro medio para hacer referencia a la variable, que no es trivial

+2

¿Por qué no eliminar MYAPP o MYAPP = undefined? – Dykam

+0

No solo la variable en sí misma, sino también cualquier cierre que pueda crearse son las funciones internas. – txwikinger

+0

@txwinker: Sí, creo que sentí que estaba implícito. Para que esto funcione, no debe haber referencias a MYAPP ni a nada dentro de él. Y hay algunos detalles delicados cuando se trata de perder memoria e IE. @Dykam: No hay razón para no estar indefinido, pero evité eliminar, ya que no tengo mucha experiencia con él, y un "1" no debería poner una gran tensión de memoria en lo que sea que el OP pueda estar haciendo. – Svend

1

¿Qué hay de cargar los archivos JS en un iframe? Luego (en teoría, nunca lo probé), puedes eliminar el iframe del DOM y eliminar la "memoria" que está usando.

creo ... o espero ...

1

Si usted está preocupado por las pérdidas de memoria a continuación, usted quiere asegurarse de que no hay controladores de eventos en el código que desea eliminar referentes a la todavía existente árbol dom

Puede ser que necesite mantener una lista de todos los controladores de eventos agregados a su código, y antes de la descarga, revise y elimine los controladores de eventos.

Nunca lo he hecho así, siempre me preocupa cuando elimino nodos que aún hay una referencia.

Aquí es un buen artículo sobre javascript pérdidas de memoria: http://javascript.crockford.com/memory/leak.html

9

(esto es bastante fuera de la manga.)

uso de memoria es de hecho un problema que necesita para estar preocupados con la actual estado actual del navegador, aunque a menos que hablemos de bastante código, no sé si el problema es el tamaño del código (generalmente es el tamaño del DOM y los manejadores de eventos sobrantes).

Puede utilizar un patrón para sus módulos cargables que lo haría mucho más fácil descargarlos en masa - o al menos, para que el navegador lo sepa puede descargarlos.

considerar:

window.MyModule = (function() { 

    alert('This happens the moment the module is loaded.'); 

    function MyModule() { 

     function foo() { 
      bar(); 
     } 

     function bar() { 
     } 

    } 

    return MyModule; 
})(); 

Eso define un cierre que contiene las funciones y foobar, que pueden llamarse entre sí de la forma habitual. Tenga en cuenta que el código fuera de las funciones se ejecuta inmediatamente.

Siempre que no pase ninguna referencia a lo que hay dentro del cierre a nada que esté fuera de él, entonces window.MyModule será la única referencia a ese cierre y su contexto de ejecución. Para descargarlo:

try { 
    delete window.MyModule; 
} 
catch (e) { 
    // Work around IE bug that doesn't allow `delete` on `window` properties 
    window.MyModule = undefined; 
} 

que le dice al entorno de JavaScript no está utilizando esa propiedad más, y hace todo lo que hace referencia disponible para la recolección de basura. Cuándo y si esa colección sucede obviamente depende de la implementación.

Tenga en cuenta que será importante si enlaza manejadores de eventos dentro del módulo para desengancharlos antes de descargarlos. Se podría hacer eso, devolviendo una referencia a una función de destructor en lugar del cierre principal:

window.MyModule = (function() { 

    alert('This happens the moment the module is loaded.'); 

    function foo() { 
     bar(); 
    } 

    function bar() { 
    } 

    function destructor() { 
     // Unhook event handlers here 
    } 

    return destructor; 
})(); 

Desenganche es entonces:

if (window.MyModule) { 
    try { 
     window.MyModule(); 
    } 
    catch (e) { 
    } 
    try { 
     delete window.MyModule; 
    } 
    catch (e) { 
     // Work around IE bug that doesn't allow `delete` on `window` properties 
     window.MyModule = undefined; 
    } 
} 
0

JavaScript intérpretes tienen los recolectores de basura. En otras palabras, si no hace referencia a nada, no los mantendrá cerca.

Una de las razones por las que es bueno usar JSON con una función de devolución de llamada (JSONP).

ejemplo, si la respuesta HTTP para cada JS es:

callback({status: '1', resp: [resp here..]}); 

Y si de devolución de llamada() no crea una referencia al objeto JSON pasado como argumento, será recolectado después de la función completa.

Si realmente necesita hacer una referencia, entonces probablemente necesite esa información por alguna razón; de lo contrario, usted NO debería haberla mencionado en primer lugar.

Los métodos mencionados para objetos de espacio de nombres solo crean una referencia que se mantendrá hasta que el recuento de referencias llegue a 0. En otras palabras, debe rastrear cada referencia y borrarla más adelante, lo que puede ser difícil cuando tiene cierres y referencias de DOM por ahí. Solo una referencia mantendrá el objeto en la memoria, y algunas operaciones simples pueden crear referencias sin que usted se dé cuenta.

0

Buen debate. Aclara un montón de cosas Sin embargo, tengo otra preocupación.

Si enlazo window.MyModule.bar() a un evento, ¿qué ocurre si el evento se desencadena accidentalmente después de que window.MyModule se elimina? Para mí, el objetivo del espaciado de nombres y la separación de js en módulos cargados dinámicamente es evitar el desencadenamiento por error de controladores cruzados de eventos.

Por ejemplo, si lo hago (excusa mi jQuery):

$ (' alguna clase.) Haga clic (window.MyModule.bar);.

¿Qué sucede si elimino window.MyModule, cargo otro módulo y hago clic en un elemento que accidentalmente tiene una clase llamada some-class?

Cuestiones relacionadas