2011-06-28 55 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