2013-06-04 13 views
6

görünümü günceller Eğik Js, oldukça standart yöntemin bu örneği düşünün: Bu elbette varsayımsal örnekBu AJAX kalıbı bir bellek sızıntısı mı?

$scope.fetchResults = function() { 
    // Some local variable that will cause creation of closure 
    var hugeData = serviceX.getMilionRecords(); 

    // Any call to any resource with success and error handlers. 
    $http({ 
     method: "GET", 
     url: "/rest-api/bulk-operation-x", 
     params: { someParam: hugeData.length } 

    }).success(function() { 
     var length = hugeData.length; 
     $scope.reportToUser("Success, that was " + length + " records being processed!"; 

    }).error(function() { 
     var length = hugeData.length; 
     $scope.reportToUser("Something went wrong while processing " + length + " records... :-("; 
    }); 
}; 

, ama güzel içinden yerel değişkenlerin kazanımına olarak tarif edilebilir biçimini göstermektedir AJAX geri aramalar. Her iki işleyicileri (success ve error) doğrudan geri arama eylemcilerden başvuruda bulunulan hugeData üzerinde bir kapatma oluştururken içinde Tabii

.

Sorum şu ki: AJAX çağrısı sonucu yalnızca başarı veya başarısızlık olabileceğinden, bu kodun yeniden kullanılması zaman içinde bellek sızıntısına neden oluyor? "Evet" cevabını verirdim, ancak bunu yerel testlerimde güvenilir bir şekilde kanıtlayamadım.

Daha deneyimli bazı gurular için bunu benim için açıklamak istiyorum. Günlük olarak Angular ile çalışan herkesin yanıtını çok isterim, ancak herhangi bir jQuery yanıtı da kabul edilir. Eğer fetchResults dış kapsam içine (hugeData erişimi olan ya da her türlü nesne veya fonksiyonu) $http() çağrısının sonucu döndüren olarak

+2

"Bellek sızıntısı", ayrılan ve sonradan hiç serbest bırakılmayan belleğe başvuran çok özel bir terimdir. Sadece bellek yönetiminin manuel olarak yapıldığı bağlamlar için geçerlidir. JS yönetiminin programlayıcıya saydam olduğu göz önünde bulundurulduğunda, bellek sızıntıları yalnızca, IE'nin eski sürümlerinde olduğu gibi, buggy uygulamasının belirli koşullar altında bellek sızıntısına neden olan kodlama kalıpları hakkında konuşursak ilgili olur. Sorunun yazılı olarak anlamlı olup olmadığından emin değilim. – Jon

+0

@ Jon'un yorumuna katılmıyorum. Kötü bir uygulama, global kapsamdaki nesneleri doldurmak gibi, bellek sızıntılarına neden olabilir. Bu durumda, geri arama bittiğinde ($ http örneği temizlenir) devData değişkeni silinir. yukarı) – rewritten

+0

@Jon, şeffaf bellek yönetimi ile herhangi bir dilde kolayca bir bellek sızıntısı yaratabilirsiniz. Java, Scala, JavaScript, C#, siz adını verin. @rewritten, tam olarak bahsettiğim şey bu. Success() 'bitirdiğinde" hugeData "öğesinin silindiğini nereden biliyorsunuz? Dil açısından, 'error()' de kullanılan kapama, ileride daha ileride yürütülebilir. Angular, kaputun altında bir şey yapmazsa (biri bittiğinde diğer geri dönüşü geçersiz kılmak gibi), o zaman burada bir bellek sızıntısı olabilir. –

cevap

4

gelir gelmez bir bellek sızıntısı olacaktır.

Kodunuzda, fetchResults'un hemen dışında büyük bir şey gösterilmez ve $http() aramasının sonucu, başarılı veya başarısız olana kadar geçerli olur, ardından karşılık gelen çağrıyı çağırır ve sonunda GC'ed olur.

anlayışlar için bakınız: @ ŁukaszBachman gözlemler http://jibbering.com/faq/notes/closures/#clIdRes

gibi bu hiçbir bellek sızıntısı olduğunu garanti etmez. Büyük nesnenize veya kapsamdaki büyük nesneye ilişkin geri bildirimlerinizle ilgili sarkan herhangi bir başvuru, üzüntüye neden olacaktır.

Yani, $q uygulamasına da bakalım ($http, $q tabanlıdır).

Eğer https://github.com/angular/angular.js/blob/master/src/ng/q.js#L191 işaretlerseniz, görebilirsiniz ertelenmiş ilk kopya resolve() yöntem yöntemine yerel bir değişken içinde kayıtlı olan geri listesi:

var callbacks = pending; 

sonradan harici pending (yani tanımlandı nullifies

pending = undefined; 

) defer seviyesinde, daha sonra bir sonraki kene de, geri aramalar yürütür. Geri bildirimin argümanı ertelenmiş bir şey olabileceği (icra için daha fazla gecikme eklenmesi) olabileceği gerçeğiyle karmaşıklaşabilir, ancak en sonunda sonsuz bir döngüye girebilirsiniz. (Ve bu komik değil!). Döngü içine girmemek için yeterince şanslıysanız, o zaman bir noktada geri arama dizisi tükenir ve daha sonra geri arama listesine herhangi bir referans yoktur, bu yüzden GC için kullanılabilir.

Ancak.

Eğer zorlarsanız işler ters gidebilir.

Arguments.callee'yi bir geri aramada kullanabilirsiniz.

Klavyenize de bira koyabilirsiniz.

Pencereden dışarı atlarsanız, birinci katta yaşamadığınız sürece, muhtemelen zarar görürsünüz.

Mutlu EcmaScripting!

+0

Neden $ http() çağrısının sonucu başarılı veya başarısız olana kadar yaşayacaksınız? AFAIU kapama JS motorunun kendimi yönetiyor, bu yüzden benim örneğimden emin olamazsın, değil mi? İkinci geri aranmanın elden çıkarıldığını doğrulamak ve böylece GC tarafından serbest bırakılabileceğini doğrulamak için '$ http' iç impl'sini kontrol etmeniz gerekir. Doğru muyum? (Okuduğum makaleye makale ekledim) –

+0

'q 'uygulamasının özellikle' resol' yöntemini kontrol edin (https://github.com/angular/angular.js/blob/master/src/ng/ q.js # L191). "Beklemede olan" geri arama zinciri, sözün çözüldüğü en kısa sürede sözünün kapsamından tamamen kaldırılır ve çözüm yönteminde başka bir değişkene içselleştirilir. Çözüm tamamlandıktan sonra, geri aramalara yönelik daha fazla referans kalmaz ve bunları GC için kullanılabilir hale getirir. – rewritten

+0

Başka bir deyişle, siz haklısınız. Ve tam olarak bu şekilde yapılır, kayıtlı geri aramaların tam listesi çözüm sürecinde temizlenir. – rewritten