Aysncronous递归方法中的回调?

时间:2016-09-28 02:23:50

标签: javascript recursion callback tree

对于我正在做的项目,我有一个基于文件及其内容构建树模型的函数。我的解析文件函数是递归的,并且将继续调用它自己,直到它无法在目录树中更深入/命中一个不包含更多文件的文件。但是,我不知道如何设置此函数的回调,因为它是递归的。到目前为止,我只是超时了我的构造树方法,但这对我的问题来说是一个可怕且不可靠的解决方案。这是我的代码:

function constructTree(dir){
  tree = new TreeModel()
  root = tree.parse({name: 'Marshall McGee Sample Pack'});
  parseFiles(dir, root, tree);
  setTimeout(function(){
    root.all().forEach(function(node){
      console.log(node.model.name);
    });
  }, 1000)
}

function parseFiles(dir, parrent, tree){
  fs.readdir(dir, function(err, files){
     if(files){
       for(i = 0; i < files.length; i++){
          parrent.addChild(tree.parse({name: files[i]}));
          console.log(files[i]);
          parseFiles(dir + "/" + files[i], parrent, tree);
       }
     }
  });
}

此代码&#34; Works&#34;但可怕的。我不知道如何确定我是否搜索了整个目录或者如何正确地执行此操作。我希望我解释得很好!谢谢,任何帮助都是appricated !!!

2 个答案:

答案 0 :(得分:1)

您应该向 parseFiles 函数添加一个回调参数,并让它在完成其工作(异步)时调用该回调。

为了知道某个文件夹中的所有项目何时被遍历,您应该保持计数,并且只有当最后一个项目完成时,才通知呼叫者(通过他提供的回调)该部分的树已完成(请参阅count变量):

function constructTree(dir){
  var tree = new TreeModel()
  var root = tree.parse({name: 'Marshall McGee Sample Pack'});
  // instead of timer, pass a callback function that should be called
  // when the whole tree has been loaded.
  parseFiles(dir, root, tree, function () {
    root.all().forEach(function(node){
      console.log(node.model.name);
    });
  });
}

function parseFiles(dir, parrent, tree, done){
  fs.readdir(dir, function(err, files){
     // Only proceed here when there is at least one file (added condition)
    if(files && files.length){
      // keep track how many items still need to be collected:
      var count = files.length;
      for(var i = 0; i < files.length; i++){
        parrent.addChild(tree.parse({name: files[i]}));
        console.log(files[i]);
        parseFiles(dir + "/" + files[i], parrent, tree, function () {
          count--;
          // if we have all items (recursively) added to the tree, notify the caller
          if (!count && done) done();
        });
      }
    } else {
      // If no information in this folder, notify caller immediately
      if (done) done();
    }
  });
}

由于调用者没有义务传递回调,因此代码必须在调用之前检查done的值。这就是if (done) done()

的原因

注意:与您的问题无关,但您应该注意使用var关键字(或letconst)以避免不必要地创建全局变量。

答案 1 :(得分:0)

每个进行的函数调用都放在堆栈中。

Step 1: constructTree 
Step 2: calls parseFiles
Step 3: calls parseFiles
.
.
.
Step n-1: calls parseFiles
Step n: cannot parse any further

此时,它将开始返回

Step n-1
Step n-2
.
.
.
Step 3
Step 2
Step 1 - and pointer returns to the original caller

让我知道,如果这解决了问题,或者您有不同的顾虑。