在招聘过程中的技能测试中,我被问到了以下问题:
var x = function(z) {
console.log(z);
if (z > 0) {
x(z-1);
}
};
为什么随着z的增加,这个算法会越来越慢?提出一种更好的版本,保持递归。我想知道答案只是为了学习。我回答说随着z的增加,递归调用次数也会增加,所以它变得越来越慢,但我无法提供更好的版本。此外,我不知道函数在z增加时为什么会变得更慢。
在招聘过程中的技能测试中,我被问到了以下问题:
var x = function(z) {
console.log(z);
if (z > 0) {
x(z-1);
}
};
正确的答案应该是:“随着z的增加,它不应该变得越来越慢。”事实上,在我的简单测试中并没有发生这种情况。在任何减速可见之前,我的测试会溢出堆栈。
我无法想象在保持其递归性质的同时编写此函数的其他替代方式。
Too much recursion
错误,并且 x(1000)
也会发生这样的错误。我认为这可能是问题所提示的,但我认为你的答案是正确的。 - James Long由于JavaScript目前还没有真正的尾调用优化,你所经历的不是基于z值的减速,而是基于堆栈增长和垃圾回收器(GC)无法清理必要保留此功能的作用域堆栈而导致的减速。
理论上,您可以通过使用setImmediate和回调模式来解决这个问题并改变这种行为。使用setImmediate允许当前执行循环的作用域在下一个GC周期期间失去使用并被收集。
因此,类似以下代码:
var x = function x(z){
console.log(z);
if (z > 0) {
setImmediate(function(){
x(z-1);
});
}
};
var x = function x(z){
console.log(z);
if (z > 0) {
setImmediate((function(newZ){
return function(){
x(newZ);
};
})(z-1));
}
};
z
,这比小量的z
指数级地慢,那么唯一真正的原因就是在大量调用堆栈顶部的函数会以某种方式变得越来越慢;即调用堆栈会积累开销。这显然在很大程度上取决于Javascript的实现。您是否运行过任何测试来确认这确实会减速? - deceze