Javascript尾部递归

Javascript尾部递归,javascript,Javascript,为什么下面的代码运行得如此。。。。慢 <html><body><script type="text/javascript"> var i = 0; f(); function f() { if (i == 5000) { document.write("Done"); } else { i++; tail(); }

为什么下面的代码运行得如此。。。。慢

<html><body><script type="text/javascript">
    var i = 0;

    f();

    function f() {
        if (i == 5000) {
            document.write("Done");
        } else {
            i++;
            tail();
        }
    }

    function tail() {
        var fn = tail.caller;
        var args = arguments;
        setTimeout(function() {fn.apply(this, args)}, 0);
    };

</script></body></html>

var i=0;
f();
函数f(){
如果(i==5000){
文件。填写(“完成”);
}否则{
i++;
尾();
}
}
函数尾(){
var fn=tail.caller;
var args=参数;
setTimeout(函数(){fn.apply(this,args)},0);
};
有几个原因:

  • 对函数对象使用
    caller
    属性会带来开销(并且是非标准的)

  • 使用
    参数
    伪数组也是如此(IIRC,这将使函数调用的速度降低2-5倍,具体取决于您使用的浏览器)

  • setTimeout
    通常需要不少于10毫秒的时间来调用函数(尽管Chrome有时会比这快一点),即使您指定0作为超时。这可能是最大的原因:10毫秒的5000次迭代等于50秒

  • 最后一项就是我说的原因:

    如果您有很多循环迭代(例如,几百次而不是15次),那么在每次迭代中进行大量循环迭代可能是值得的,而不是在每次迭代中屈服;产量需要一段可测量的时间(通常约10-15毫秒)

    …在我对你的回答中

    请注意,无需使用
    调用者
    参数
    ,即可重写代码,从而使代码更加清晰:

    var i = 0;
    
    f();
    
    function f() {
        if (i == 5000) {
            document.write("Done");
        } else {
            i++;
            setTimeout(f, 0);
        }
    }
    
    单独:我注意到您使用了
    文档。在代码示例中编写
    。如果在页面解析过程中执行代码(这是唯一可以使用
    document.write
    )而不是在页面解析后使用事件处理程序触发的代码中执行此操作,则不能使用
    setTimeout
    。这是因为通过
    document.write
    输出的代码必须在页面加载时与HTML解析器同步运行。脚本块在解析过程中执行的原因正是:如果它们发出HTML,解析器必须处理它们。如果您想在解析后修改页面(我建议这样做),那么您需要使用DOM方法来获取元素引用,然后使用DOM方法添加到元素中,或者(运行起来更简单、更快)在元素上设置
    innerHTML
    属性

    从这两个问题中,我的感觉是,你可能确实想研究一下,并且只使用上面的方法作为浏览器的后备(例如,我恐怕,但我打赌IE9会有它们——而且所有其他主要的浏览器现在都有了它们)。

    有几个原因:

  • 对函数对象使用
    caller
    属性会带来开销(并且是非标准的)

  • 使用
    参数
    伪数组也是如此(IIRC,这将使函数调用的速度降低2-5倍,具体取决于您使用的浏览器)

  • setTimeout
    通常需要不少于10毫秒的时间来调用函数(尽管Chrome有时会比这快一点),即使您指定0作为超时。这可能是最大的原因:10毫秒的5000次迭代等于50秒

  • 最后一项就是我说的原因:

    如果您有很多循环迭代(例如,几百次而不是15次),那么在每次迭代中进行大量循环迭代可能是值得的,而不是在每次迭代中屈服;产量需要一段可测量的时间(通常约10-15毫秒)

    …在我对你的回答中

    请注意,无需使用
    调用者
    参数
    ,即可重写代码,从而使代码更加清晰:

    var i = 0;
    
    f();
    
    function f() {
        if (i == 5000) {
            document.write("Done");
        } else {
            i++;
            setTimeout(f, 0);
        }
    }
    
    单独:我注意到您使用了
    文档。在代码示例中编写
    。如果在页面解析过程中执行代码(这是唯一可以使用
    document.write
    )而不是在页面解析后使用事件处理程序触发的代码中执行此操作,则不能使用
    setTimeout
    。这是因为通过
    document.write
    输出的代码必须在页面加载时与HTML解析器同步运行。脚本块在解析过程中执行的原因正是:如果它们发出HTML,解析器必须处理它们。如果您想在解析后修改页面(我建议这样做),那么您需要使用DOM方法来获取元素引用,然后使用DOM方法添加到元素中,或者(运行起来更简单、更快)在元素上设置
    innerHTML
    属性


    从这两个问题中我的感觉是,您可能确实想研究一下,并且只使用上面的内容作为浏览器的后备(例如,我恐怕,但我打赌IE9会有它们,而且所有其他主要的浏览器现在都有了它们)。

    非常感谢您的解释!我一定会调查网络工作者!!非常感谢您的解释!我一定会调查网络工作者!!