2013-08-29 13 views
15

Sto usando jquery-ui Tabs e sto riscontrando un problema che si verifica quando una scheda è stata rimossa. La scheda sembra essere rimossa, insieme al suo content div, ma quando dai un'occhiata all'heap in Chrome DevTools Profiles (dopo che una scheda è stata rimossa) vedrai che gli elementi tab li e div sono ancora presenti, ma distaccati . Nel tempo, l'aggiunta/rimozione ripetuta delle schede causa l'accumulo di questi elementi. Ad esempio, se si aggiunge una scheda di 10 volte, ci saranno 10 elementi div unifamiliari e 10 elementi li staccati mostrando nell'istantanea mucchio:Non riesco a ripulire elementi DOM distaccati

Heap snapshot with detached elements

ho le seguenti viste:

TabLabel = Marionette.ItemView.extend({ 
    template: "#tab-label", 
    tagName: "li", 
    events: { 
     "click .ui-icon-close": "closeTab" 
    }, 
    closeTab: function(e) { 
     this.$el.contents().remove(); 
     this.model.collection.remove(this.model); 
     $("#main-container").tabs("refresh"); 
     this.close(); 
    } 
}); 

TabContainer = Marionette.ItemView.extend({ 
    template: "#tab-container", 
    tagName: "div", 
    onBeforeRender: function() { 
     this.$el.attr("id", "div-" + this.id); 
    }, 
    onClose: function() { 
     // This removes the region that contains the container 
     App.layout.removeRegion(this.containerRegion); 
    } 
}); 

TabLabels = Marionette.CollectionView.extend({ 
    tagName: "ul" 
}); 

TabContainers = Marionette.CollectionView.extend({ 
    tagName: "div" 
}); 

le viste sono istanziati in questo modo:

tabs = new TabsCollection(); // Create a new collection instance 

var tabLabelView = new TabLabels({ 
    itemView: TabLabel, 
    collection: tabs 
}); 

var tabContainerView = new TabContainers({ 
    itemView: TabContainer, 
    collection: tabs 
}); 

come si può vedere, i punti di vista sia riferiscono alla stessa collezione; ogni modello della collezione può essere detto che rappresenta una singola scheda (solo così accade che il modello contenga le informazioni necessarie per soddisfare le schede jquery-ui). Le viste sono mostrate in una regione tramite Marionette.Layout ... piuttosto standard. L'aggiunta di una scheda si ottiene facendo clic su un collegamento nel contenitore della scheda; tutto ciò non fa altro che aggiungere un altro modello alla raccolta e quindi chiamare le schede ("aggiorna") sul contenitore principale, che mostra la nuova scheda. Rimozione di una scheda si ottiene facendo clic su un'icona "X" nell'angolo in alto a destra della scheda.

Ho passato molto tempo a cercare di rintracciare questa perdita e non riesco a capire se si tratta di un problema nel mio codice (il modo in cui sto chiudendo viste/modelli/ecc. Forse?) O se è un problema nel plugin jquery-ui tabs.

Pensieri? Grazie in anticipo!

Update # 1 Come richiesto, ecco un jsfiddle dimostrando il problema - basta chiudere le schede e vedrete che gli elementi staccati sono lasciati alle spalle.

Inoltre, uno screenshot:

enter image description here

Aggiornamento # 2 Questo sembra essere una perdita nelle schede jquery-ui widget. Lo stesso comportamento si verifica nello widget demonstration sul sito Web jquery-ui. Ho aggiunto un paio di schede e poi ha chiuso e abbastanza sicuro, hanno insistito:

enter image description here

Ho provato questo con l'ultima (al momento della stesura di questo) versione di jQuery UI (1.10.3) e la versione precedente (1.10.2).

+0

Puoi pubblicare un jsfiddle dimostrando questo? – Rooster

+2

Mi chiedo se il problema è che il gestore eventi che non viene rimosso –

+0

@JaniHartikainen ho pensato che potrebbe essere il problema, ma ho provato a chiamare più permutazioni di unbind() nella funzione close e i risultati sono gli stessi. – musashiXXX

risposta

3

Così alla fine ho risolto questo problema (un bel po 'di tempo fa) facendo due cose:

  1. per scavo jQueryUI a favore di Bootstrap
  2. Modifica della funzione closeTab (vedere l'originale jsFiddle) al seguente :

    closeTab: function (e) { 
        e.stopPropagation(); 
        e.preventDefault(); 
        this.model.collection.remove(this.model); 
        this.close(); 
    } 
    

In questo frammento, stopPropagation e preventDefault sono davvero quello che si fermò questo elemento da rimanente distaccato (e accumulando su successivi aggiunge/rimuove) nel DOM. Per riassumere: questo problema è stato creato non chiamando stopPropagation/preventDefault sull'oggetto evento dopo che è stato attivato. Ho aggiornato il jsFiddle in modo che rimuove correttamente gli elementi della scheda e per i posteri, ecco uno screenshot del risultato:

Updated jsFiddle

Come si può vedere, nessuno degli elementi della scheda sono rimasti staccati dopo aver fatto clic "X" per chiuderli. Gli unici elementi distaccati sono quelli che provengono dall'interfaccia di jsFiddle.

3

C'è un motivo per cui si utilizza this.$el.contents().remove() anziché this.$el.empty()?

L'utilizzo di this.$el.empty() in quel jsFiddle sembrava risolvere il distaccato NodeList.

Alcuni profiling di memoria note:

  • orologio http://www.youtube.com/watch?v=L3ugr9BJqIs
  • Utilizzare il metodo 3 istantanee, 2 non è sufficiente. Cosa significa?
    • nuovo inizio, la modalità in incognito e rinfrescato
    • Acquisisci fotogramma (GC forzata accadrà ogni volta che si prende un'istantanea)
    • Fai qualcosa, fotografia istantanea (gc)
    • fare qualcosa di simile, fotografia istantanea (gc)
    • Confronta snapshot 2 con un'istantanea 1, trovare delta con +
    • Scegli Sintesi e oggetti assegnate tra il 1 e 2 istantanee per la fotografia istantanea 3
    • Cerca elementi che hai trovato confrontando 2 e 1 che non dovrebbero essere lì. Questi sono i porri

ho trovato casi in cui jQuery sembra porro perché salvare l'oggetto jQuery attuale .prevObject quando facendo alcune operazioni come chiamare .add(). Forse quella chiamata allo .contents() fa un po 'di magia funky.

+0

Ho provato questo, usando .empty() invece di .contents(). remove() e purtroppo i risultati sono gli stessi. – musashiXXX

Problemi correlati