如何使这个同步递归函数异步

时间:2011-11-14 18:19:03

标签: javascript asynchronous recursion

我有一个javascript函数,递归地遍历树。它有两个“标志”变量,在函数本身的范围之上设置为false或true,因此如果在递归“walkTree”函数时将标志设置为true,则每次递归都是如此。另一方面,for循环可能存在带有返回的函数,如果有的话。我遇到的问题是当递归太多时我会收到错误。

我想通过使这个递归函数异步来防止这个问题,我已经尝试将for循环中的子walkTree()调用放入setTimeout,但我现在遇到的问题是函数的其余部分在完成其余异步操作之前,将执行(并可能返回错误的值)。那么我怎样才能使这个异步同时仍然确保返回正确的值(而不是递归中的顶级函数调用)?

正如您所看到的,函数的结尾使用了所有调用共享的flagB“变量”,因此我们需要确保所有递归调用都已完成(并返回一些内容),然后才能检查这些条件。谢谢!

var flagA = false;
var flagB = false;

var walkTree = function (n) {
  var sub;

  for (var i = 0; i < n.children.length; i++) {
      sub = walkTree(n.children[i]);
      if (sub === 'something-special') {
        return sub;
      }
  }

  var test = doSomethingWith(n);

  if (test === "something") {
    flagA = true;
  }

  if (test === "something-else") { 
    flagB = true;
  }

  if (flagB === true) {
    return true;
  }
  if (test === "something-special") {
    return test;
  } else {
    return false;
  }

}

2 个答案:

答案 0 :(得分:1)

使用超时来走树,认真吗?您是否考虑过使用迭代树遍历而不是递归?

示例:

var walkTree = function(node) {
    var queue = [node];
    while (queue.length) {
        var n = queue.shift();
        for (var i = 0; i < n.children.length; i++) {
            queue.push(n.children[i]);
        }
        doSomethingWith(n);
    }
}

另见this so questionwikipeida article

答案 1 :(得分:1)

正如alex vasi建议的那样,您可能需要考虑迭代树遍历而不是递归。但是,如果您的数据集很大并且处理数据需要花费大量时间,那么您的UI可能会冻结。因此,您仍然可能希望异步进行处理。

这是对alex的例子的修改:

function asyncIterativeWalkTree(node) {
    var queue = [node];

    var processQueue = function() {
        var n = queue.shift();
        for (var i = 0; i < n.children.length; i++) {
            queue.push(n.children[i]);
            setTimeout(processQueue, 0);
        }
        doSomethingWith(n);
    }

    processQueue();
}

上面的代码片段以异步方式进行迭代遍历,从而为UI提供了一些自我更新的时间。

这是一个jsFiddle,您可以注意到同步和异步遍历之间的区别。同步遍历使您的浏览器冻结一小段时间,而异步版本在浏览器处理树时给浏览器一些时间。 (代码有点乱,对不起......)

编辑:更新了jsFiddle