【问题标题】:Recursive function calling in JavaScriptJavaScript 中的递归函数调用
【发布时间】:2011-08-18 02:19:44
【问题描述】:

我知道在 JavaScript 中对函数进行递归调用时应小心行事,因为第二次调用可能会慢 10 倍。

Eloquent JavaScript 状态:

有一个重要问题:在大多数 JavaScript 实现中,第二个版本比第一个版本慢大约 10 倍。在 JavaScript 中,运行一个简单的循环比多次调用一个函数要便宜很多。

John Resig 甚至在 this 帖子中说这是一个问题。

我的问题是:为什么使用递归效率如此之低?它只是特定引擎的构建方式吗?我们会在 JavaScript 中看到不是这种情况的时间吗?

【问题讨论】:

  • 我猜这是一个范围问题:P 好问题,我很好奇他们的答案是什么!
  • 函数调用开销简直比循环控制要大;在几乎任何编程语言中都是如此。调用函数时还有很多工作要做:分配和初始化新作用域、保存返回地址、编组参数等。请注意,JavaScript 解释器的速度越来越快,所以性能提示在 3一年前的博文(或书籍)应该受到质疑。
  • “因为你的第二次通话可能会慢 10 倍” 这不是文字所说的。它说第二个版本的代码慢了 10 倍。
  • This 很好地展示了递归有多慢。请注意,不同的不仅仅是函数调用,因为两个测试的调用次数相同

标签: javascript recursion


【解决方案1】:

由于更改堆栈和设置新上下文等的所有开销,函数调用比简单循环更昂贵。为了使递归非常有效,语言必须支持某种形式的尾调用消除,这基本上意味着将某些类型的递归函数转换为循环。 OCaml、Haskell 和 Scheme 等函数式语言可以做到这一点,但我所知道的 JavaScript 实现都没有这样做(除非它们都这样做,否则它只会有一点用处,所以也许我们遇到了哲学家进餐的问题)。

【讨论】:

【解决方案2】:

这只是构建浏览器使用的特定 JS 引擎的一种方式,是的。如果没有尾调用消除,每次递归时都必须创建一个新的堆栈帧,而使用循环它只是将程序计数器设置回它的开头。例如,Scheme 将其作为语言规范的一部分,因此您可以以这种方式使用递归,而不必担心性能。

https://bugzilla.mozilla.org/show_bug.cgi?id=445363 表示 Firefox 正在取得进展(Brendan Eich 在这里谈到它可能会成为 ECMAScript 规范的一部分),但我认为目前的任何浏览器都没有实现这一点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多