AngularJS - $ destroy olay dinleyicilerini kaldırır mı?


200

https://docs.angularjs.org/guide/directive

Bu olayı dinleyerek bellek sızıntılarına neden olabilecek olay dinleyicilerini kaldırabilirsiniz. Kapsamlara ve öğelere kaydedilen dinleyiciler yok edildiğinde otomatik olarak temizlenir, ancak bir hizmette dinleyici kaydettiyseniz veya silinmeyen bir DOM düğümünde dinleyici kaydettiyseniz, kendiniz temizlemeniz veya bellek sızıntısı yapma riskiyle karşı karşıyasınız.

En İyi Uygulama: Direktifler kendiliğinden temizlenmelidir. Yönerge kaldırıldığında bir temizleme işlevi çalıştırmak için element.on ('$ destroy', ...) veya scope. $ On ('$ destroy', ...) kullanabilirsiniz.

Soru:

Benim element.on "click", (event) ->iç yönergem var:

  1. Yönerge imha edildiğinde, element.onçöp toplanmasını önlemek için herhangi bir bellek referansı var mı?
  2. Açısal belgeler, gönderilen olaydaki olay dinleyicilerini kaldırmak için bir işleyici kullanmam gerektiğini belirtir $destroy. destroy()Olay dinleyicilerini çıkardığına inanıyordum , durum böyle değil mi?

Yanıtlar:


433

Olay dinleyicileri

Öncelikle iki tür "olay dinleyicisi" olduğunu anlamak önemlidir:

  1. Kapsam etkinliği dinleyicileri şu yolla kaydedildi $on:

    $scope.$on('anEvent', function (event, data) {
      ...
    });
  2. Örneğin onveya yoluyla öğelere eklenmiş olay işleyicileri bind:

    element.on('click', function (event) {
      ...
    });

$ Kapsamı. $ İmha ()

Ne zaman $scope.$destroy()yürütüldüğünde bu aracılığıyla kaydedilen tüm dinleyicileri kaldırır$on o $ kapsamına.

O will not DOM öğelerini veya ikinci türden herhangi ekli olay işleyicileri kaldırın.

Bu, $scope.$destroy()bir direktifin bağlantı işlevi içinde örneğin manuel olarak çağrılmasının , örneğin üzerinden element.onveya DOM öğesinin kendisinden eklenmiş bir işleyiciyi kaldırmayacağı anlamına gelir .


element.remove ()

Bunu not et remove (jQuery angularjs önce yüklü ise bir jQuery yöntemi) ve standart bir DOM Eleman Nesne üzerinde bulunmayan bir jqLite yöntemidir.

Bu element.remove()öğe yürütüldüğünde ve tüm alt öğeleri DOM'den kaldırılacak tüm etkinlik işleyicileri örneğinelement.on .

Bu olacak değil öğesiyle ilişkili $ kapsamını yok.

Daha karmaşık hale getirmek için ayrıca bir jQuery olayı var $destroy. Bazen öğeleri kaldıran üçüncü taraf jQuery kitaplıklarıyla çalışırken veya bunları manuel olarak kaldırırsanız, bu durumda temizlik yapmanız gerekebilir:

element.on('$destroy', function () {
  scope.$destroy();
});

Bir direktif "yok edildiğinde" ne yapmalı

Bu direktifin nasıl "yok edildiğine" bağlıdır.

Normal bir durum, ng-viewgeçerli görünümü değiştirdiği için bir direktifin yok edilmesidir. Bu olduğunda, ng-viewyönerge ilişkili $ kapsamını yok eder, üst kapsamına yapılan tüm başvuruları keser ve çağırır.remove() ve öğeyi .

Başka bir deyişle, bu görünüm, tarafından yok edildiğinde bağlantı işlevinde bununla bir yönerge içeriyorsa ng-view:

scope.$on('anEvent', function () {
 ...
});

element.on('click', function () {
 ...
});

Her iki olay dinleyicisi de otomatik olarak kaldırılacaktır.

Bununla birlikte, bu dinleyicilerin içindeki kodun, örneğin ortak JS bellek sızıntısı desenine ulaştıysanız, bellek sızıntılarına neden olabileceğini unutmayın circular references.

Bu normal direktif durumunda bile, görünümün değişmesi nedeniyle imha edilirken, manuel olarak temizlemeniz gerekebilecek şeyler vardır.

Örneğin, bir dinleyici kaydettiyseniz $rootScope:

var unregisterFn = $rootScope.$on('anEvent', function () {});

scope.$on('$destroy', unregisterFn);

Bu gerekli çünkü $rootScope uygulamanın ömrü boyunca hiçbir zaman yok edilmediğinden .

$ Kapsamı yok edildiğinde otomatik olarak gerekli temizliği gerçekleştirmeyen başka bir pub / sub uygulaması kullanıyorsanız veya direktifiniz hizmetlere geri çağrılar iletirse de aynı şey geçerlidir.

Başka bir durum iptal etmek olacaktır $interval/ $timeout:

var promise = $interval(function () {}, 1000);

scope.$on('$destroy', function () {
  $interval.cancel(promise);
});

Direktifiniz olay işleyicilerini örneğin geçerli görünümün dışındaki öğelere eklerse, bunları da manuel olarak temizlemeniz gerekir:

var windowClick = function () {
   ...
};

angular.element(window).on('click', windowClick);

scope.$on('$destroy', function () {
  angular.element(window).off('click', windowClick);
});

Bunlar, direktifler Angular tarafından "yok edildiğinde" ng-viewya da örneğin ne yapılacağına dair bazı örneklerdi ng-if.

DOM öğelerinin yaşam döngüsünü vb. Yöneten özel direktifleriniz varsa, elbette daha karmaşık hale gelecektir.


4
'$ rootScope uygulamanın ömrü boyunca hiçbir zaman yok edilmez.' : bir kez düşündüğünüzde açıktır. Ben de bunu kaçırıyordum.
user276648

@tasseKATT Burada küçük bir soru, Aynı denetleyicide farklı etkinlikler için birden fazla $ rootScope. $ açıksa, $ scope. $ on ("$ destroy", ListenerName1); her $ rootScope için. $ farklı ??
Yashika Garg

2
@YashikaGarg Muhtemelen tüm dinleyicileri çağıran bir yardımcı fonksiyona sahip olmak en kolay olurdu. $ Scope. $ On ('$ destroy') gibi, function () {ListenerName1 (); ListenerName2 (); ...}); İzole olmayan kapsamlardaki olay işleyicilerinde $ için ek karmaşıklık var mı? Veya kapsamları iki yönlü bağlamalarla izole etmek mi?
David Rice

Olay dinleyicilerini $ rootscope'a neden kaydettirmeliyim? Olay dinleyicilerini $ kapsamına kaydederim ve diğer denetleyiciler $ rootscope.broadcast ('eventname') gerçekleştirir ve olay dinleyicilerim çalışır. $ Olay kapsamındaki bu olay dinleyicileri hala otomatik olarak temizlenecek uygulama olaylarını dinliyor mu?
Skychan

@Skychan Üzgünüm yorumunuzu kaçırdım. Bu bir tahmindir, ancak insanlar $rootScopebu nedenle kullanabilir : stackoverflow.com/questions/11252780/… Yanıtın üstte belirtildiği gibi, bunun değiştiğine dikkat edin. Evet, $scopebu kapsam yok edildiğinde normal olay dinleyicileri otomatik olarak temizlenir.
tasseKATT
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.