2014-09-01 19 views
9

Supponiamo di avere una pagina con un layout a due colonne in cui la colonna di sinistra è un insieme di collegamenti e carica la pagina/modello html associato nella colonna destra quando viene fatto clic su quel collegamento.Eventi ed elementi DOM

Una volta caricato un modello, c'è un gestore di template che viene inizializzato come un singleton tramite requirejs e definisce alcuni metodi ei gestori come:

SomePage.prototype.saveHandler: function(e) { ... }; // Page handler has a handler 

SomePage.prototype.initialize: function() { 
    $('#btnSave').on('click', saveHandler); 
} 

Poi, sto allegando eventi DOM attraverso un metodo initialize ogni il tempo di caricamento della pagina.

SomePage.initialize(); // This attaches the click event 

Ora, quando clicco un altro link sulla sinistra, una pagina di modello diverso viene caricata e il processo di cui sopra si ripete per quella pagina.

Mi chiedo cosa succede all'evento click che è stato allegato in precedenza all'elemento btnSave? È ora un gestore di eventi penzoloni nella cache jQuery?

Se tento di rimuoverlo quando la stessa pagina si carica nuovamente, rimuoverà effettivamente l'evento originale?

$('#btnSave').off('click', saveHandler); 

L'esecuzione del seguente blocco impedisce perdite di memoria/riferimenti ciondoli?

// The potential problem here is that btnSave is part of the newly loaded template 
// and not the element i attached the handler to earlier (which doesn't exist anymore) 
$('#btnSave').off('click', saveHandler); 

$('#btnSave').on('click', saveHandler); 

Qual è il modo migliore per garantire che non si ottengano riferimenti pendenti e perdite di memoria. Questa è una potenziale domanda anche per plain javascript. La mia comprensione è che quanto sopra non funzionerà quando la pagina di modello viene aggiornata. Nel frattempo sto andando a sperimentarlo, ma sarebbe bello sapere come lo gestiscono gli esperti. Grazie!

+1

Io sicuramente uso 'off' e poi' on' subito dopo, come hai fatto tu. Ma esiste un modo per chiamare "off" * prima * di ricaricare il template? – dthree

+0

Ho pensato a questo schema come soluzione, ma non sono sicuro di averne ancora bisogno perché jQuery potrebbe gestirlo internamente.Se ogni pagina implementava un'interfaccia e al momento del caricamento si registrava come la pagina corrente, allora un gestore globale di collegamenti poteva fare qualcosa come app.cache.currentPage.cleanup() che poteva contenere tutte le alternative. – theoutlander

+2

Penso che tu abbia ragione nel senso che crea un elemento fantasma non facendolo ... – dthree

risposta

0

Quando si carica il nuovo tmpl è necessario allegare solo l'evento per questo. Per esempio:..

$ ("# btnSave", $ (newly_tmpl)) il ("click", .....

1

Date un'occhiata a questa diapositiva da Andy Osmani un guru javascript Avrete trovare la risposta sulla perdita di memoria e riferimenti circolari qui: https://speakerdeck.com/addyosmani/javascript-memory-management-masterclass

+0

Grazie per aver postato. È fantastico! Conosco gli strumenti di memoria nel debugger di Chrome. Uno di questi giorni cercherò di trovare un po 'di tempo per profilarlo attraverso il profiler di memoria e scoprire il mistero. Un'altra cosa che finirò per fare è esaminare la sorgente di jQuery. Penso che una soluzione semplice per questo sarebbe quella di introdurre funzionalità che consentano di trasmettere un identificatore univoco al momento della registrazione dell'evento e jQuery internamente potrebbe sostituire il gestore esistente con il nuovo. – theoutlander

0

Invece di attaccare evento click al pulsante, è necessario collegare sulla funzione click per il tempo di esecuzione tasto dopo il carico modello come questo

var element = $("<div id='tempDiv' class='main_container o-hidden'><button value='Click' id='btnSave'/></div>"); 

$("#btnSave",element).each(function(){ 
    $(this).attr("onclick","tryMe();"); 
}); 

e. allegherà la funzione tryMe click al tuo b utton, la variabile elemento dovrebbe essere creata dal contenuto del tuo modello.

0

Perché non semplicemente renderlo più di un evento delegato e solo registrarsi una sola volta:

$(".someParentThatsAlwaysOnPage #btnSave").on("click", function() { 
    var somePage = getMeContextOfProperObject(); 
    somePage.saveHandler(); 
}); 

In questo modo l'evento click è legato solo una volta e jQuery aggiornerà la portata ascoltatore come i cambiamenti DOM. Tutto quello che dovresti fare è fornire un mezzo per ottenere l'oggetto appropriato. Senza vedere altro del tuo codice non posso aiutarti.

+0

Grazie! Save è solo un esempio. La maggior parte delle pagine avrà ascoltatori di eventi diversi in base al loro contenuto. Il tuo suggerimento è buono, ma funziona solo se ci fosse un'interfaccia che ogni pagina potrebbe implementare. Tuttavia, ciò non è fattibile in questo caso perché le pagine non hanno un denominatore comune dopo aver salvato/annullato il tipo di funzionalità. – theoutlander