2011-06-28 79 views
3

我正在處理的項目中存在一個奇怪的問題。這會自動更改圖像源和div的內容。jquery遞歸函數中的奇怪無限循環bug

我編寫了一個函數,但它陷入了無限循環而頁面沒有加載(頁面總是顯示加載頁面)。

這些代碼:

$.fn.extend({ 
    changehaber: function(a){ 
    $('#cokokunanlarcontent').fadeOut('slow',function() { 
      $('.jquerycokokunanlarbutton').attr('src','images/sabah/buton-pasif.png'); 
      $('img[rel="'+a+'"]').attr('src','images/sabah/buton-aktif.png'); 
     }).html($('#'+a).html()).fadeIn('slow'); 
     return this; 
    } 
}); 

function slidecokokunanlar() { 
    $('#cokokunanlarcontent').html($('#cokokunanlar1').html()).delay(3000).changehaber('cokokunanlar2').delay(3000).changehaber('cokokunanlar3').delay(3000).changehaber('cokokunanlar4').delay(3000).changehaber('cokokunanlar5').delay(3000); 
    slidecokokunanlar(); 
} 

slidecokokunanlar(); 

什麼是這裏的問題,這是執行的時候,我希望函數無限的工作,但頁面顯示它總是加載。這是控制檯輸出:

Uncaught RangeError: Maximum call stack size exceeded 

在此先感謝

回答

5

您不能在不阻止整個執行堆棧的情況下從內部調用函數。通過從內部調用函數,可以有效地防止它返回,並且由於Javascript是單線程的,所有內容都會停下來!

改變你的函數是:

function slidecokokunanlar() { 
    $('#cokokunanlarcontent').html($('#cokokunanlar1').html()).delay(3000)... 
    setTimeout(slidecokokunanlar, 0); 
} 

這樣就可以併發執行而不會阻塞UI,從而使你的頁面保持響應。

有關如何工作的更多信息,請參閱this article on "chunking"

+3

你得到了「setTimeout」參數,函數名不應該用引號引起來。 – Pointy

+1

是!編輯。謝謝! :) –

+0

工程很好,標記爲接受,謝謝! – Arda

2

這是因爲JavaScript doesn't have proper tail calls

你的函數自己永遠調用自己。第一個不會完成並返回,第二個也不會完成並返回,也不會執行其中的任何一個,直到您耗盡堆棧並爆炸爲止。

您可以嘗試使用setTimeout代替。查看example on jsFiddle

編輯您可能不想使用0,除非您真的需要它連續運行。即使使用100,您也要每秒執行10次該功能。

function foo(){ 
    console.log('foo'); 
    setTimeout(foo, 0); 
} 

foo(); 
1

這是一個更乾淨的方式來做到這一點。

var coko = $('#cokokunanlarcontent');    // cokokunanlarcontent 
var cokos = $('[id^="cokokunanlar"]').not(coko); // cokokunanlar1..2..3 etc 

var total = cokos.length; // total quantity 

var i = 0; 

var allow = true; 

$('.jquerycokokunanlarbutton').attr('src','images/sabah/buton-pasif.png'); 

function slidecokokunanlar(isRestart) { 

    if(!isRestart) { 
     $('img[rel="' + cokos[i].id + '"]').attr('src','images/sabah/buton-aktif.png'); 

     coko.html(cokos.eq(i).html()) 
      .fadeIn('slow'); 
    } 
    if(allow) { 
     coko.delay(3000) 
      .fadeOut('slow', function() { 
       i = (++i % total); 
       slidecokokunanlar(); // recursively call with next index or 0 
      }); 
    } 
} 

slidecokokunanlar(); // start it off 

function restartSlider() { 
    allow = true; 
    slidecokokunanlar(true); 
} 

function stopSlider() { 
    allow = false; 
} 

stopSlider(); // to stop it 

restartSlider(); // to restart it 
+0

謝謝,我也想過這個,但是我正在改變的圖像將不得不停止函數(動畫的改變),我正在通過(clearTimeout(變量))來做這個變量,它是「var variable = setTimeout(functionname,0);「我無法用類似的方法來管理它。你的方法怎麼可能? – Arda

+0

@Arda:每次執行遞歸函數調用時都要檢查一下標誌,比如'var allow = true;'。這個變量當然需要在'slidecokounalar()'函數之外。當你想停止遞歸時,將標誌設置爲'false'。要重新啓動它,請將該標誌設置爲「true」,並調用「slidecokounalar()」。如果你想讓它在剩下的地方拾取它,把'i'放在函數外部的一個變量中,並且每次更新它,而不是將它作爲參數傳遞。我會更新我的答案來實現這些想法。 – user113716

+0

已更新。我給了'slidecokokunanlar();'一個特殊的'isRestart'參數,這樣如果它正在重新啓動(而不是第一次啓動),它不會嘗試加載和「fadeIn」已經顯示的內容。 – user113716