【问题标题】:how to make this synchronous recursive function asynchronous如何使这个同步递归函数异步
【发布时间】:2011-11-14 18:19:02
【问题描述】:

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

我想通过使这个递归函数异步来防止这个问题,我尝试将 for 循环内的 sub 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;
  }

}

【问题讨论】:

  • 异步函数无法返回有用的值,需要提供回调函数作为参数。
  • 为什么不在循环遍历元素(参数)之前检查它们是否有子元素?
  • 是的,在我的实际功能中我正在做 if (n.children != undefined && n.children.length > 0)
  • 我仍然不太清楚作为参数的回调函数是如何递归的。也不知道该怎么做。谢谢,
  • 不确定你的函数应该做什么,以及你是否打算在函数之外使用变量。该函数从不返回"something-special",但您正在检查if 语句中的返回值。

标签: javascript asynchronous recursion


【解决方案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();
}

上面的代码 sn-p 进行异步迭代遍历,从而给 UI 一些时间来更新自身。

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

编辑:更新 jsFiddle

【讨论】:

  • 啊!非常好,谢谢!我会尝试使这个异步,看看它是否有时对 UI 有帮助。谢谢!
【解决方案2】:

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

例子:

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

【讨论】:

  • 谢谢,会调查的。我一直在尝试使这个递归函数工作,我没有想过寻找另一种方法。
  • 请注意,如果您的树很大,您可能仍希望使用异步解决方案以防止 UI 冻结。
猜你喜欢
  • 2023-03-23
  • 1970-01-01
  • 1970-01-01
  • 2017-03-12
  • 2016-09-21
  • 1970-01-01
  • 2021-12-12
  • 2018-02-24
  • 2023-03-11
相关资源
最近更新 更多