2009-08-28 25 views
12

Sto scrivendo un'applicazione web con una "shell" esterna statica e una sezione di contenuto dinamico. La sezione del contenuto dinamico ha molti aggiornamenti man mano che gli utenti navigano nel sistema. Quando viene caricato un nuovo blocco di contenuti, può anche caricare facoltativamente un altro file JavaScript. Nel nome di una buona pulizia, rimuovo i blocchi di script dal DOM che si applicano ai vecchi blocchi di contenuto, dal momento che quel JavaScript non è più necessario.È possibile scaricare JavaScript caricato dinamicamente?

Il problema si presenta in seguito, quando ho realizzato che sebbene io abbia rimosso l'elemento <script> dal DOM, il JavaScript precedentemente valutato è ancora disponibile per l'esecuzione. Questo ha un senso, ovviamente, ma sono preoccupato che possa causare una perdita di memoria se gli utenti navigano in molte sezioni diverse.

La domanda quindi è: dovrei essere preoccupato per questa situazione? In tal caso, c'è un modo per forzare il browser a ripulire JavaScript stantio?

risposta

14

<theory> Si potrebbe andare con un approccio più orientato agli oggetti e costruire il modello in modo che ogni blocco di blocchi javascript entri come i propri oggetti, con i propri metodi. Al momento dello scaricamento, è sufficiente impostare tale oggetto su null. </theory>

3

Se si salva il codice valutato in spazi dei nomi, come ad esempio:

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

"liberare" il tutto dovrebbe essere semplice come l'impostazione MYPP a qualche valore casuale, ala

MYAPP = 1 

Ciò dipende dal fatto che non ci sono altri mezzi per fare riferimento alla variabile, che non è banale

+2

Perché non eliminare MYAPP o MYAPP = non definito? – Dykam

+0

Non solo la variabile stessa, ma anche tutte le chiusure che potrebbero essere create sono le funzioni all'interno. – txwikinger

+0

@txwinker: Sì, credo di averlo sentito implicito. Affinché funzioni, non devono esserci riferimenti né a MYAPP né a qualcosa al suo interno. E ci sono alcuni dettagli pignoli quando si tratta di perdere memoria, e IE. @Dykam: Nessuna ragione per non andare indefinito, ma ho evitato di cancellare, dato che non ho molta esperienza con esso, e un "1" non dovrebbe mettere a dura prova la memoria su ciò che l'OP potrebbe fare. – Svend

1

Come si fa a caricare i file JS in un iframe? Quindi (in teoria, non ho mai provato da solo) è possibile rimuovere l'iframe dal DOM e rimuovere la "memoria" che sta usando.

credo ... o spero ...

1

Se siete preoccupati per le perdite di memoria, allora si vuole essere certi che non ci sono i gestori di eventi nel codice che si desidera rimuovere riferiscono alla tuttora esistente albero di dom.

È possibile che sia necessario mantenere un elenco di tutti i gestori di eventi aggiunti dal codice e, prima di effettuare lo scaricamento, passare e rimuovere i gestori di eventi.

Non l'ho mai fatto in quel modo, mi preoccupo sempre quando togli i nodi che c'è ancora un riferimento.

Ecco un buon articolo su javascript perdite di memoria: http://javascript.crockford.com/memory/leak.html

9

(questo è abbastanza off-the-bracciale.)

uso di memoria è in effetti un problema è necessario essere interessati con l'attuale lo stato dell'arte del browser, sebbene a meno che non stiamo parlando di un bel po 'di codice, non so che la dimensione del codice sia il problema (di solito è la dimensione DOM e i gestori di eventi rimanenti).

È possibile utilizzare un modello per i moduli caricabili che renderebbe molto più facile scaricarli in massa, o almeno, per consentire al browser di conoscerlo, possibile scaricarli da.

consideri:

window.MyModule = (function() { 

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

    function MyModule() { 

     function foo() { 
      bar(); 
     } 

     function bar() { 
     } 

    } 

    return MyModule; 
})(); 

Che definisce una chiusura che contiene le funzioni foo e bar, che possono chiamare reciprocamente in modo normale. Si noti che il codice al di fuori delle funzioni viene eseguito immediatamente.

A patto che non si rinviino riferimenti a ciò che è contenuto nella chiusura a qualcosa al di fuori di esso, quindi window.MyModule sarà l'unico riferimento a tale chiusura e al relativo contesto di esecuzione. Per scaricarlo:

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

che racconta l'ambiente JavaScript non si sta usando più che la proprietà, e fa tutto ciò che fa riferimento a disposizione per la raccolta dei rifiuti. Quando e se tale raccolta avviene è ovviamente dipendente dall'implementazione.

Si noti che sarà importante se si agganciano i gestori di eventi all'interno del modulo per sganciarli prima dello scaricamento. Si potrebbe fare che restituendo un riferimento a una funzione distruttore al posto della chiusura principale:

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; 
})(); 

Sganciamento è quindi:

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 interpreti hanno netturbini. In altre parole, se non fai riferimento a qualcosa, non li terrà in giro.

Uno dei motivi per cui è opportuno utilizzare JSON con una funzione di callback (JSONP).

esempio, se HTTP di risposta per ogni JS è:

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

E se callback() non crea un riferimento all'oggetto JSON passato come argomento, sarà garbage collection dopo la funzione completa.

Se è davvero necessario fare un riferimento, probabilmente è necessario che i dati in giro per qualche motivo - altrimenti sarebbe/non dovrebbe aver fatto riferimento in primo luogo.

I metodi menzionati per gli oggetti dello spazio dei nomi creano solo un riferimento che verrà mantenuto fino a quando il conteggio dei riferimenti arriva a 0. In altre parole, è necessario tracciare ogni riferimento ed eliminarlo in un secondo momento, che può essere difficile quando si hanno chiusure e riferimenti dal DOM in giro. Solo un riferimento manterrà l'oggetto in memoria e alcune semplici operazioni possono creare riferimenti senza che tu te ne accorga.

0

Bella discussione. Cancella un sacco di cose. Ho un'altra preoccupazione, però.

Se collego window.MyModule.bar() a un evento, cosa accade se l'evento viene attivato per errore dopo che window.MyModule è stato eliminato? Per me, l'intero punto di namespacing e separazione di js in moduli caricati dinamicamente consiste nell'evitare di attivare i gestori di eventi cross-module per errore.

Per esempio, se faccio (scusa il mio jQuery):

$ (' un po' di classe.) Clicca (window.MyModule.bar);.

Cosa succede se elimino window.MyModule, carico un altro modulo e clicco su un elemento che accidentalmente ha una classe chiamata some-class?

Problemi correlati