Kevin, bu özel kod snippet'inin nasıl çalıştığını (neden oldukça anlaşılmaz olduğu ile birlikte) kısaca belirtiyor, ancak genel olarak trambolinlerin nasıl çalıştığı hakkında bazı bilgiler eklemek istedim .
Kuyruk çağrısı optimizasyonu (TCO) olmadan, her işlev çağrısı geçerli yürütme yığına bir yığın çerçeve ekler . Diyelim ki sayıları geri saydırabilecek bir işleve sahibiz:
function countdown(n) {
if (n === 0) {
console.log("Blastoff!");
} else {
console.log("Launch in " + n);
countdown(n - 1);
}
}
Eğer countdown(3)
ararsak, çağrı yığınının TCO olmadan nasıl görüneceğini analiz edelim.
> countdown(3);
// stack: countdown(3)
Launch in 3
// stack: countdown(3), countdown(2)
Launch in 2
// stack: countdown(3), countdown(2), countdown(1)
Launch in 1
// stack: countdown(3), countdown(2), countdown(1), countdown(0)
Blastoff!
// returns, stack: countdown(3), countdown(2), countdown(1)
// returns, stack: countdown(3), countdown(2)
// returns, stack: countdown(3)
// returns, stack is empty
TCO ile, her özyinelemeli çağrı için countdown
ise kuyruk pozisyonunda hiçbir yığın çerçevesi tahsis edilir (çağrının sonucu döndüren dışında yapmak şey kalmadı). TCO olmadan, yığın hafifçe bile olsa genişler n
.
Tramplenleme, countdown
fonksiyonun etrafına bir sarmalayıcı takarak bu kısıtlamanın üstesinden gelir . Ardından, countdown
özyinelemeli aramalar yapmaz ve hemen aranacak bir işlevi döndürür. İşte örnek bir uygulama:
function trampoline(firstHop) {
nextHop = firstHop();
while (nextHop) {
nextHop = nextHop()
}
}
function countdown(n) {
trampoline(() => countdownHop(n));
}
function countdownHop(n) {
if (n === 0) {
console.log("Blastoff!");
} else {
console.log("Launch in " + n);
return () => countdownHop(n-1);
}
}
Bunun nasıl çalıştığını daha iyi anlamak için çağrı yığınına bakalım:
> countdown(3);
// stack: countdown(3)
// stack: countdown(3), trampoline
// stack: countdown(3), trampoline, countdownHop(3)
Launch in 3
// return next hop from countdownHop(3)
// stack: countdown(3), trampoline
// trampoline sees hop returned another hop function, calls it
// stack: countdown(3), trampoline, countdownHop(2)
Launch in 2
// stack: countdown(3), trampoline
// stack: countdown(3), trampoline, countdownHop(1)
Launch in 1
// stack: countdown(3), trampoline
// stack: countdown(3), trampoline, countdownHop(0)
Blastoff!
// stack: countdown(3), trampoline
// stack: countdown(3)
// stack is empty
Her At adım countdownHop
fonksiyonu terk yerine o ne anlatır çağırmak için bir işlev dönen, bundan sonra ne olur doğrudan kontrolünü gibi sonra ne. Trambolin fonksiyonu o zaman bu alır ve onu çağırır, o zaman ne olursa olsun fonksiyonu çağıran o hayır "Bir sonraki adım" kalmayıncaya kadar böyle devam döndürür ve. Buna trambolin işlemi denir, çünkü kontrolün akışı her yinelemeli çağrı ile doğrudan yinelenen işlev yerine, trambolin uygulaması arasında "sıçrar". Özyinelemeli çağrı yapan kim üzerindeki kontrolünü bırakarak , trambolin işlevi yığının çok büyük olmamasını sağlayabilir. Not: bu uygulama, trampoline
sadelik için değer döndüren ihmalleri içermektedir.
Bunun iyi bir fikir olup olmadığını bilmek zor olabilir. Yeni bir kapanış sağlayan her adım nedeniyle performans düşebilir. Akıllıca optimizasyonlar bunu mümkün kılabilir, ancak asla bilemezsiniz. Trambolin oluşturma, örneğin, bir dil uygulaması maksimum arama yığını boyutu belirlediğinde, sabit özyineleme sınırlarını aşmada yararlıdır.
loopy
taşmadığı için kendisini çağırmaz .