2014-10-05 13 views
12

State cercando per un po 'negli archivi e sulla rete per una risposta, ma non trovandone veramente uno, solo frammenti. Sembra che ci siano molti post suggeriti, ma nessuno di questi ha la risposta.

Ho una direttiva complessa che utilizza scope: true. In realtà è l'ultima versione 2.x di ng-grid che sto cercando di scrivere codice cleanup, dal momento che sta semplicemente perdendo memoria come un matto, e la nostra app è "bloccata" per ora. Ecco the plunk that demos the problem. Quando fai clic sulla griglia e controlli le istantanee dell'heap in seguito, vedrai diversi oggetti "non collegati" ngGrid. Questi sono tenuti solo dagli ascoltatori sulla portata della direttiva.

Quando cambio stato (utilizzando ui.route più recente) facendo clic su più griglie (stati), l'ambito della direttiva griglia riceve l'evento $ destroy. Il gestore sta funzionando. Tuttavia, lo scope stesso NON sta ricevendo $ destroy() su di esso. Vedo nell'istantanea dell'heap che l'ambito della direttiva continua a contenere elementi tramite $$ ascoltatori. Inoltre, scope. $$ distrutto non è impostato.

Tuttavia, ambito. prototipoIS distrutto. E perché è, non riesco nemmeno a chiamare $ portata $ distruggo da $ on-$ distruggere gestore della direttiva, dal momento che il $ proto distruggere() chiamata ha cambiato la definizione di $ distruggere a noop:.

ngGridDirectives.directive('ngGrid', ['$compile', '$filter', '$templateCache', '$sortService', '$domUtilityService', '$utilityService', '$timeout', '$parse', '$http', '$q', 
    function($compile, $filter, $templateCache, sortService, domUtilityService, $utils, $timeout, $parse, $http, $q) { 
    var ngGridDirective = { 
    scope: true, 
    compile: function() { 
     return { 
     pre: function($scope, iElement, iAttrs) { 
      $(iElement).on('$destroy', function cleanupElementNgGrid() { 
       $timeout(function() { 
       $scope.$destroy(); 
       $scope.destroyedByForce = true; 
       console.log("I destroyed it."); 
       },4000); 
      }); 
     ... 

Impostazione dell'ambito. $$ ascoltatori = {} con un timeout $ di 2000 (per dare il tempo che la direttiva finisca di ripulire nel mio ascoltatore on- $ destroy sembra funzionare, ma è sbagliato munge con gli interni, ea volte è . non abbastanza a lungo per il browser per completare la pulizia E 'solo un work-around/kludge

ho provato anche questo:.

Così che cosa sta impedendo di mia direttiva portata f rom ricevendo automaticamente $ destroy() su di esso?

In un primo momento, ho pensato che fosse perché usiamo scope: true nelle opzioni direttiva, dal momento che il prototipo sembra essere stato distrutto. Così ho scritto a plunk to try that theory out. Ma con questo plunk, l'ambito della direttiva viene adeguatamente distrutto e non viene trapelato alcun oggetto. Molto sorprendente, in realtà. Ma io non uso la stessa vista di nidificazione che ho nel primo plunk; tuttavia dubito che sia così. L'ambito del controller viene ancora cancellato quando le visualizzazioni cambiano. Ho ancora un osservatore su un oggetto interno. Quindi penserei di vedere una dinamica simile. Ma sembra che $ destroy sia davvero chiamato su quel ambito interno.

Qualche idea su cosa impedirebbe a un ambito di direttiva di ottenere $ destroy() su di esso? L'IT sembra correlato allo scopo: vero bit, ma non riesco abbastanza a ingannare gli interni angolari abbastanza da dire perché.

Grazie in anticipo,

Jesse


Update: OK, vi posterò un aggiornamento a questo problema.

Per quanto mi riguarda, sembra che quello che sta succedendo sia che l'ambito principale dell'elemento (non l'ambito semi-isolato per la direttiva grid) ottiene $ destroy() d. Tuttavia, l'ambito secondario che utilizza tale ambito come prototipo è molto probabilmente il salvataggio del metodo $ destroy in anticipo, perché self. $$ distrutto è vero (eredità prototipale). Quindi gli ascoltatori e gli osservatori non vengono chiariti.

Probabilmente potrei aggiornare la direttiva per essere completamente isolata nella portata, ma non ho il tempo di risolverne le implicazioni.

Ho anche scoperto che è più che solo $ destroy. Lo stesso $ scope ha un sacco di funzioni definite su di esso dalla direttiva che forma la chiusura attorno ai vars interni che contengono molta memoria.

Così, ho scritto un servizio che fornisce una pulizia aggiuntiva che è facilmente iniettabile nella direttiva di griglia discutibile. Ho un plunk che lo demo, ma non posso postarlo nel pezzo principale a causa della mia bassa reputazione :). Ora puoi cambiare griglie come preferisci e nessuna tranne le griglie attuali rimarranno nell'heap.

Spero che questo aiuti qualcuno che va in avanti,

J

+1

Ecco il collegamento all'altro plunk che mostra la risoluzione di cui sopra. http://plnkr.co/edit/r2uTKTJW2yJTbHx0kXYB – jessewolfe

+0

Ciao, ho avuto un problema che penso sia correlato, hai trovato il motivo per cui $ destroy non viene chiamato nell'ambito? http://stackoverflow.com/questions/27467210/angular-directive-memory-leaks – Barnash

+0

Forse interessante: questo articolo parla di interruzioni che possono accadere nella catena $ destroy a causa di cattive creature dei sotto-ambiti (ovvero: jquery) http: //www.bennadel.com/blog/2706-always-trigger-the-destroy-event-before-removing-elements-in-angularjs-directives.htm – Offirmo

risposta

1

Non so se questo è più adatto come un commento o no. Recentemente ho lavorato a un grande progetto che ha utilizzato ng-grid + angularjs e abbiamo avuto tutti i problemi che hai riscontrato: perdite di memoria a gran voce. Abbiamo scoperto che in effetti non tutto veniva pulito bene e che gli oscilloscopi e gli orologi erano trapelati dappertutto.

Abbiamo provato ad aggiungere una logica personalizzata per provare a fare una pulizia migliore ma non ha risolto il nostro problema al 100%. I nostri problemi sono stati accentuati anche dallo scrolling orizzontale + dalla virtualizzazione su ng-grid, quindi potrebbe essere utile tenerlo a mente (se ricordo che stavano pensando di sistemarlo in una versione futura).