как сделать эту синхронную рекурсивную функцию асинхронной - PullRequest
6 голосов
/ 14 ноября 2011

У меня есть функция JavaScript, которая рекурсивно обходит дерево.Он имеет две переменные "flag", которые установлены в false или true выше области действия самой функции, и поэтому, если флаг установлен в true один раз, когда функция "walkTree" рекурсивна, он будет истинным для каждой рекурсии,С другой стороны, цикл for может существовать и с функцией return, если что-то для.Проблема в том, что при слишком большом количестве рекурсий я получаю сообщение об ошибке.

Я бы хотел предотвратить эту проблему, сделав эту рекурсивную функцию асинхронной, я попытался поместить вызов sub walkTree () внутри цикла for в setTimeout, но теперь у меня проблема в том, что остальныефункции будет выполнен (и может вернуть неправильное значение), прежде чем остальная часть асинхронного материала будет выполнена.Итак, как я могу сделать это асинхронным, в то же время убедившись, что верное значение будет возвращено (а не вызов функции top в рекурсии)?

Как видите, конец функции использует эту «переменную» 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 ]

1 голос
/ 15 ноября 2011

Как предположил Алекс Васи, вы можете рассмотреть итеративный обход дерева вместо рекурсивного.Однако, если ваш набор данных огромен и обработка данных занимает много времени, ваш пользовательский интерфейс может зависнуть.Таким образом, вы все еще можете выполнять асинхронную обработку.

Вот модификация примера Алекса:

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();
}

Приведенный выше фрагмент кода выполняет итеративный обход асинхронно, что дает некоторое время пользовательскому интерфейсу.обновить себя.

Вот jsFiddle , где вы можете заметить разницу между синхронным и асинхронным перемещением.Синхронный ход заставляет ваш браузер зависать на небольшой период времени, в то время как асинхронная версия дает браузеру некоторое время для дыхания при обработке дерева.(Код немного запутанный, извините ...)

Редактировать: Обновлен jsFiddle

1 голос
/ 14 ноября 2011

Серьезно используете таймауты для прогулки по дереву?Рассматривали ли вы использовать итерационный обход дерева вместо рекурсивного?

Пример:

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);
    }
}

Также см. этот вопрос и статья в Википедии

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...