0

我来自 c++ 背景,所以对回调机制不太清楚。与 java-script 混淆以实现递归。有人请帮忙。

这就是我想要实现的。

Method 1(on success - call Method2);
Method 2(on success - call Method3);
Method 3(on success - call Method1)

这是我的代码。

function Method1(val1, val2, callback) {
   console.log('Method1' + val1);
   callback(val1, Method3);
}

function Method2(val1, fn) {
  console.log('Method2 ' + val1);
  val1++;
  fn(val1);
}

function Method3(val){
    console.log('Method3 ' + val);
    val++;
    if(val > 1000)  process.exit(0);
    else {
        Method1(val,2, Method2);
    }
}

Method1(1,2,Method2);

一旦我运行它,它就会抛出RangeError: Maximum call stack size exceeded错误。如何在javascript中实现递归?

编辑:我正在写一个网络爬虫。这就是我想要实现的。

1. Get the URL to be crawled.
2. Store the content(webpage) in a file. 
3. Parse the content. Get all the links in the file. 
4. call step 2 for each link in the content.

这只能在递归中实现。我知道必须有终点/出口点。一旦我解析了所有网络链接,我的退出点可能就在这里。它应该退出。

4

4 回答 4

2

您需要说明何时停止,否则它将继续调用每个方法,从而导致您的错误。

于 2013-11-04T10:59:41.317 回答
1

Javascript 不支持尾调用优化。一切都只是压入堆栈,但在达到最终情况之前不会弹出。

在满足结束条件之前,您正在最大化堆栈大小。

有什么办法可以克服吗?

有多种方法,但我认为最简单的方法是setTimeout稍后使用参数调用您的函数。


例如:

function count(n, end) {
    console.log(n);
    if (n < end) {
        count(n+1, end);
    }
}
count(0, 100000) // More than enough to exceed the stack limit

这将尝试打印从 0 到 100000 的所有数字,但它在到达末尾之前达到了最大堆栈大小。


因此,您可以通过将其传递给函数来延迟执行时间,而不是直接调用它,该setTimeout函数将获取函数及其参数并在以后运行它。使用的另一个好处setTimeout是调用将是异步的,这意味着其他代码可以同时运行。

function count(n, end) {
    console.log(from);
    if (n < end) {
        setTimeout(count, 0, n+1, end);
    }
}
count(0, 100000) // More than enough to exceed the stack limit, but it will run!

有关调度如何工作的更多信息:http: //ejohn.org/blog/how-javascript-timers-work/

于 2013-11-04T15:37:02.710 回答
0
function Method1(<params>){
   // condition
   if(<params>){
      Method2(<params>);
   }else{
      return;
   }

}

function Method2(<params>){
   // condition
    if(<params>){
      Method3(<params>);
   }else{
      return;
   }
}

function Method3(<params>){
   // condition
    if(<params>){
      Method1(<params>);
   }else{
      return;
   }
}

Method1(<params>);

注意:它需要一些条件来打破递归循环,否则它不会结束循环。

于 2013-11-04T11:04:13.653 回答
0

它可以通过 setImmediate 或 setTimeout 或 process.nextTick(nodejs) 函数来实现。有效的方法是 setImmediate。以下链接中给出的原因。

Setimmdiate API:http
: //nodejs.org/api/timers.html#timers_setimmediate_callback_arg SetImmediate vs nextTick(SO):setImmediate vs. nextTick
说明1:http ://www.nczonline.net/blog/2013/07/09/ the-case-for-setimmediate/
解释 2:http ://howtonode.org/understanding-process-next-tick

据我所知,某些浏览器不支持 SetImmediate。到目前为止,它仅在 IE10 中受支持。在服务器端,nodejs 支持这些 api。

于 2013-11-05T05:59:57.610 回答