【问题标题】:recursive function completes before recursive calls finish递归函数在递归调用完成之前完成
【发布时间】:2013-07-18 18:05:21
【问题描述】:

我是 javascript 新手,对异步方面、闭包等方面没有真正的能力。我已经对此进行了几天的研究,并进行了大量的试验和错误,但似乎无法解决我的问题,即是:

我正在尝试遍历树结构,收集所有底层节点(那些没有子节点的节点)。该节点数据被加载到全局数组中(不是最佳但需要)。我使用的 walk 函数是递归的。但是异步性质导致对函数的第一次调用在递归调用返回之前返回,因此不会询问完整的树。我尝试将它放在一个匿名函数中,该函数似乎可以遍历整个树,但是没有加载全局数组(无法访问?)。

顺便说一句,实际代码位于单独的隔离网络上,因此无法直接剪切和粘贴到此处。下面是相关部分的功能等效项(除非我打错了)。对此表示歉意。任何帮助将不胜感激。

var nodeList = new Array(); // global variable

function someFunction(rootNode) {
   // unrelated processing here
   walkTree(rootNode);   // gather the childless nodes
   return;
}

function walkTree(node) {
   return function() {   // required in order traverse the entire tree
                         // but with it, nodeList does not get populated
      var num = node.numChildren();
      var childNodes = node.getChildNodes();
      for (var i=0; i<num; i++)  {
         var currentNode = childNodes.item(i);
         if (currentNode.numChildren() > 0) {
            walkTree(currentNode);
         }
         else {
             var obj = new Object();
             /// extract certain attributes of current node here
             /// and make a variant 
             nodeList[nodeList.length] = obj;
         }
      } // END for
   } // close anonymous function
} // END FUNCTION 

【问题讨论】:

  • 你确定这是异步的吗?在我看来它不像。
  • 我看不到异步...
  • 这段代码不计算任何东西。对walkTree(rootNode) 的调用会创建一个匿名函数并将其返回,但不会调用该匿名函数。目前尚不清楚您要通过此完成什么。需要异步执行吗?
  • 也许我使用了错误的术语。我所知道的是 walkTree 函数在连续递归调用完成之前返回,因此树只是部分加载。我习惯于执行停止直到递归完成的语言。对不起,红鲱鱼。
  • 正如@TedHopp 所说,它返回一个函数,但它不调用该函数(这就是为什么walkTree 没有被调用并且你的数组没有被填充)。该函数的每次调用都会返回一个函数,然后需要调用该函数,该函数将返回一个函数......等等......所以我怀疑你不需要匿名函数构造,而只是想执行它代码。

标签: javascript recursion closures anonymous-function


【解决方案1】:

如果你不需要异步执行,你的代码可以简化:

var nodeList = [];

function someFunction(rootNode) {
   // unrelated processing here
   walkTree(rootNode);   // gather the childless nodes
   return;
}

function walkTree(node) {
   var num = node.numChildren(),
       childNodes = node.getChildNodes();
   for (var i=0; i<num; i++)  {
      var currentNode = childNodes.item(i);
      if (currentNode.numChildren() > 0) {
         walkTree(currentNode);
      }
      else {
         var obj = new Object();
         /// extract certain attributes of current node here
         /// and make a variant 
         nodeList.push(obj);
      }
   }
}

如果您确实需要异步执行,则实施将取决于您使用的异步机制(网络工作者、使用 setTimeout 的模拟、Clumpy 之类的框架等)。

例如,对于 Clumpy,您可以这样编码(未经测试):

var nodeList = [],
    clumpy = new Clumpy();

function someFunction(rootNode) {
   // unrelated processing here
   walkTree(rootNode);   // gather the childless nodes
   return;
}

function walkTree(node) {
   var num = node.numChildren(),
       childNodes = node.getChildNodes(),
       i;
   clumpy.for_loop(
       function() { i = 0; },
       function() { return i < num; },
       function() { i++; },
       function() {
           var currentNode = childNodes.item(i);
           if (currentNode.numChildren() > 0) {
              walkTree(currentNode);
           }
           else {
              var obj = new Object();
              /// extract certain attributes of current node here
              /// and make a variant 
              nodeList.push(obj);
           }
       }
   );
}

【讨论】:

  • 感谢您的建议。我取出了匿名函数。剩下的就是你上面的东西(非块状版本)。正如您所猜测的那样,它不能解决大型或深度嵌套的树结构的问题。对 walkTree 的后续(递归)调用在原始调用返回之前没有完成;即 push() 没有被执行。它适用于小型/简单节点。有什么方法可以保证在程序继续之前在 javascript 中完成函数调用?
  • @user2596595 - 您是如何得出对walkTree 的顶级调用过早返回的结论的?我认为这对于我的第一个代码是不可能的。该方法将阻塞,直到所有递归调用完成。
  • 我添加了一个全局变量debugCounter。它在 someFunction 中的 walkTree 调用之前被初始化。它在推送之前的 else 语句中递增。它的工作原理取决于我发送它的树。对于稀疏树,它计算正确,对于密集/深度嵌套树,它只达到 1。我正在使用在代码中的另一个点调用的警报。 (Firebug 未获准用于主机系统,因此调试是一项挑战。)
  • @user2596595 - 如果结构遍历函数按预期运行,我看不出这怎么可能。 childNodes.item(i) 是否有可能返回 undefinednull,或者当有孩子时 node.numChildren() 返回 0 或负数?您能否在允许 Firebug 的浏览器上重现该行为,或者在具有内置等效功能(例如 Chrome)的浏览器中重现该行为?
  • Chrome 也未获批准。我坚持使用 IE9,特别是 32 位版本。我添加了对未定义类型和 numChildren
猜你喜欢
  • 2014-12-11
  • 2021-06-26
  • 2017-06-22
  • 2021-09-19
  • 1970-01-01
  • 2012-03-27
  • 1970-01-01
  • 2021-11-11
  • 2012-10-27
相关资源
最近更新 更多