2015-07-06 20 views
9

Dizi listesi çok büyükse, aşağıdaki özyineleme kodu neden yığın taşmasına neden oluyor? Bunu nasıl düzeltebilirim ve özyinelemeyi hala koruyabilirim?Özyinelemeli işlevde büyük bir dizi işlenirken taşma taşması

var list = readHugeList(); 

var nextListItem = function() { 
    var item = list.pop(); 

    if (item) { 
     // process the list item... 
     nextListItem(); 
    } 
}; 
+8

JavaScript'in çok sınırlı arama yığını boyutu vardır. ES6 için uygulamalar güncellendiğinde bu durumun değişmesi gerektiğine inanıyorum çünkü uygun kuyruk çağrıları IIRC'nin bir parçası. Bunu düzeltmek için senkronize olmayan gruplar halinde yapmanız gerekir, ancak bu kodunuzun bir geri arama gerektirmesini sağlayacaktır. –

+1

@quint Ayrıca, bazı tarayıcılarda maksimum çağrı yığını 1400'ün biraz üzerindedir. Bu, Opera 12.17 ve feryat durumudur. Bir çözüm, 1 milisaniyeden bir 'setTimeout' kullanmak olacaktır. –

+0

@IsmaelMiguel: Wow, Opera için düşük olduğunu hiç bilmiyordum. Delilik bu. –

cevap

4

Bu çok garip gelecektir, ancak bir setTimeout kullanın. Bunun gibi

:

//fill it with 50000 elements 
var list = Array(50001).join('1.1').split('.'); 

var nextListItem = function() { 
    var item = list.pop(); 

    if (item) { //should be list.length 

     // recursion here! 
     setTimeout(nextListItem, 0); 

    } 
}; 
nextListItem(); 

tekrarlama şimdi sonsuz olduğunu!

Bazı tarayıcıların oradaki 0 hoşuna gitmediğine dikkat edin.
Bir yan etki olarak kodunuz tarayıcıyı engellemez.

+0

Tüm tarayıcılar '0' veya herhangi bir falsey değerinde başarısız olur. Listeyi mutasyona soktuğunuz için, temel durumunuz 'list.length' kontrol edilmelidir. Ayrıca, her öğe için yeni bir 'setTimeout 'yerine toplu işlerde bir çözüm yapmak çok daha verimli olacaktır. Asla bir "0" zamanlayıcı değil, bu yüzden uzunca bir zaman alabilir. Yaptıklarına bağlı olarak başka komplikasyonlar da var. –

+0

@squint Haklısınız. Onun sonsuz yinelemesine sahip olmak için neler yapabileceğini gösterdim. Ve evet, oldukça uzun bir süre alır (Yaklaşık 50 saniye), ancak kod engelleme olmayan bir şekilde yürütülür, bu yüzden, 'kinda' iyi. –

+0

[Kaynak makale] 'yi (https://www.toptal.com/javascript/interview-questions), yığın taşması sorununa bir çözüm olarak' setTimeout 'kullanılmasını da tavsiye ederim. ** Bu sorunu çözmek için 'setTimeout' KULLANMAYIN ** - daha fazla bilgi için, konuyla ilgili incelememi okuyun: https://stackoverflow.com/a/43596323/633183 – naomik

0

Sadece bir diziden geçiyor gibi görünüyor. Basit bir for döngü kullanmayı denediniz mi?

var list = readHugeList(); 
for (var i = 0; i < list.length; i++) { 
    //Do something with list[i] 
} 
+1

Bu, özümün soru gerektirdiği gibi kalmaz. Eminim "for" döngüsünün nasıl çalıştığını biliyordur. –

+0

@squint Hemen hemen tüm ön uç web geliştiricilerinin basit bir döngü için ne olduğunu bilmesini beklerim, ancak onun profili ruby-on-ray geliştiricisi diyor. Sadece bu değil, karmaşık kod ile basit sorunları basitçe çözmeyi deneyen pek çok geliştiriciye rastladım, çünkü bu sadece beyninin işleyiş şeklidir. –

+0

Olabilir. Yine de, o, özellikle, özyineliği * korumak istiyordu (ki bu, zorunlu çözümlerin hakkında bilgi sahibi olduğunu gösteriyor) *. 'For' döngüsü demek mantıklı değil. Sadece söylüyorum gerçekten soruyu cevaplamıyor. Açıkçası, özyinelemeyle daha kolay çözülen bazı problemler var. –

İlgili konular