2013-07-22 25 views
0

我看W3Schools的網絡工作者網頁,並發現此代碼:本質上是遞歸函數資源密集型嗎?

var i=0; 

function timedCount() 
{ 
i=i+1; 
postMessage(i); 
setTimeout("timedCount()",500); 
} 

timedCount(); 

兩個問題:

  1. 這被認爲是一個遞歸函數?
  2. 如果是,是否資源密集?

我不是遞歸函數的性質完全清楚,但我記得聽到每一個遞歸調用被存儲在存儲器中的某個地方。這對所有遞歸函數都是如此嗎?如果它運行足夠長的時間,該功能是否會最終堵塞內存?

謝謝!

回答

3

這是而不是遞歸,因爲timedCount在下一個實例被調用之前退出。 這只是一個自我延續的延遲循環,如果你想這樣稱呼它的話。 (順便說一句,這將是更好的使用setInterval,而不是反覆使用setTimeout處理這個例子是一些非常糟糕的代碼,最W3Fools資源。)

timedCount() -> setTimeout() -> end 
    ^    | 
    |    | 
    +----------------+ 

是一個遞歸函數:

function recurse() { 
    recurse(); 
} 

這裏一個調用堆棧建成後,外recurse不會退出並熄滅堆棧直到內recurse調用返回,這將不會返回,直到它內部recurse呼叫回報等無限。由於在這裏的任何地方都沒有return,這最終會打碎堆棧;所以有你的資源使用。

recurse() -> recurse() -> recurse() -> recurse() -> recurse() -> ... 
+0

非常感謝您的詳細解答。 –

0

每個函數都在內存中。

真正遞歸函數消耗每次調用(像所有其他功能)的堆棧空間,重要的是有多少遞歸。

我不考慮例如「遞歸」因爲timedCount原始通話結束之前計時器到期後,它再次調用。如果是這樣的:

function timedCount() { 
    i = i + 1; 
    postMessage(i); 
    timedCount(); 
} 

那簡直是遞歸的,而且會非常迅速地吹你的堆棧,因爲沒有terminatal條件。

2

一般情況下,遞歸可以優化,但您可以放心地假定JavaScript實現沒有對遞歸進行優化。

關於你提到的兩個具體問題:

  1. 這不是嚴格意義上的遞歸函數。遞歸函數在函數體中的某個地方調用。timedCount函數總是返回控制權,從不直接或間接調用它自己。在這種情況下,它將控制返回到頁面的事件循環,以便稍後由定時器再次調用。
  2. 這意味着它確實嘗試確保自己將被再次調用,但因爲它不直接調用它自己,它不會填充堆棧空間。因此它不會隨着時間的推移堵塞內存。

timedCount的強大之處在於它在返回之前不能被再次調用。 無視並行。

+0

看到deceze的答案實際上體面的例子。 – Jabokoe

+0

無論如何JavaScript沒有並行性。 – millimoose

+0

@millimoose通常是的,但它一直有興趣將其作爲潛在的加速因子。我記得在JavaScript中使用了一個並行粒子引擎。當然還有Parallel.js API。我知道......這一切與原來的問題無關。 – Jabokoe