【问题标题】:Asynchronously Perform Recursive Data Tree Construction?异步执行递归数据树构造?
【发布时间】:2014-07-02 16:24:09
【问题描述】:

我正在开发一个使用文件树的 Web 应用程序。前端 JavaScript 向我的 Node.js 服务器执行 ajax 请求,该服务器调用我的 browse2 导出函数。然后,此函数负责为我的函数 getFolderContents() 提供正确的路径,该函数递归地构建文件系统层次结构对象结构。

我的问题是我目前正在同步做事。在研究过 Node.js 的内部工作原理之后,似乎我应该不惜一切代价避免同步操作。因此,我想将我的代码转换为异步工作。但是,我无法让它发挥作用,而且我的所有解决方案都很复杂。

我尝试使用“异步”包管理流程。我没有运气弄清楚这一点。我尝试实现自己的计数器/循环/回调系统来确定进程何时完成执行。最终,我想我无法将注意力集中在异步执行流程上。

我想问两个问题: 1.在这种情况下,同步执行这个请求而不是异步执行这个请求会不会有害? 2.如果第一个问题是,我应该如何将这段代码转换为异步的?

注意:当我尝试异步执行操作时,我使用了每个同步函数的异步对应项。

以下是我的同步(工作)代码:

var path = require('path');
var fs = require('fs');

exports.browse2 = function(request, response) {
    var tree = getFolderContents('C:\\Users\\AccountName\\folder1\\folder2\\folder3\\test\\');

    response.send(tree);
};


function getFolderContents(route) {
    var branch = {};
    branch.title = path.basename(route);
    branch.folder = true;
    branch.children = [];

    var files = fs.readdirSync(route);
    var size = files.length;

    for (var i = 0; i < size; i++) {
        var file = files[i];
        var concatPath = path.join(route, file);

        if (fs.lstatSync(concatPath).isDirectory())
            branch.children.push(getFolderContents(concatPath));
        else
            branch.children.push({
                "title" : path.basename(file),
                "path" : file
            });
    }

    return branch;
}

感谢所有的意见!

编辑:

添加了异步代码尝试。没有完全工作。只接收到树的一部分。

    exports.browse2 = function(request, response) {
        getFolderContents(
                'C:\\Users\\AccountName\\folder1\\folder2\\folder3\\test\\',
                function(tree) {
                    response.send(tree);
                });
    };

function getFolderContents(route, callback) {
    var branch = {};
    branch.title = path.basename(route);
    branch.folder = true;
    branch.children = [];

    fs.readdir(route, function(err, files) {
        files.forEach(function(file) {
            var concatPath = path.join(route, file);

            fs.lstat(concatPath, function(err, stats) {
                if (stats.isDirectory())
                    branch.children.push(getFolderContents(concatPath, callback));
                else
                    branch.children.push({
                        "title" : path.basename(file),
                        "path" : file
                    });

                callback(branch);
            });         
        });
    });
}

【问题讨论】:

    标签: javascript multithreading node.js asynchronous recursion


    【解决方案1】:

    您遇到的基本问题是,当您使用异步调用时,您不能只将事物分配给函数的返回。异步的全部意义在于函数不会等待。比如:

    function get_data(a) {
        var data = some_async_call(a);
    
        //at this point, data is undefined because execution won't wait on the calls to finish
    
        data.do_something();  // this breaks because of the above
    }
    

    因此,您要做的是将匿名函数传递给称为回调的异步函数,并且一旦操作实际完成,异步函数就会调用该函数。上面的例子会变成这样:

    function get_data(a) {
        some_async_call(a, function(data) {
            data.do_something();
        });
    }
    
    function some_async_call(variable, callback) {
        call_async({
            data: variable,
            success: callback
        });
    }
    

    在你的情况下,它看起来像这样:

    exports.browse2 = function(request, response) {
        getFolderContents('C:\\Users\\AccountName\\folder1\\folder2\\folder3\\test\\', function(tree) {
            response.send(tree);
        });
    };
    
    function getFolderContents(route, callback) {
        var branch = {};
        branch.title = path.basename(route);
    
        ...
    
        callback(branch);
    }
    

    如果您熟悉 setTimetout,这就是它的工作原理 - 设计模式是传递一个匿名函数来完成这项工作,然后一旦数据/信息实际可用,该函数就会执行。

    【讨论】:

    • 感谢您的建议。我对这件事仍然很困惑。
    • 格式有点乱——现在应该看起来更好了。我还将对该问题添加更一般的解释。
    • 这对我来说开始变得更有意义了。我已经编辑了我原来的问题,以展示我目前对异步代码的看法。它目前只能部分工作。似乎我的树中只有一部分最终成为发送的响应。感谢您的解释。
    • 抱歉在这里发表评论,但我还没有对原始问题发表评论的权限。您的代码对我来说看起来是正确的,有几件事要尝试/提出问题:如果您单独调用 fs.readdir,它是否像您期望的那样工作?文件是否在每次调用时都未定义,还是在递归调用堆栈中的某个地方中断?另外,我自己没有 node.js 可以测试,但我发现这个问题可能很重要/相关:stackoverflow.com/questions/5827612/…
    • 好的,谢谢。这个问题是相关的和有帮助的。我将继续尝试并使用您所说的以及其他线程中所说的内容。
    【解决方案2】:

    我设法让它工作。以下是我对自己问题的回答:

    1. 最好以异步方式执行任务,否则将意味着应用程序将阻止其他用户接收他们的响应,直到后续请求得到响应。

    2. 将同步代码转换为异步代码的方法是使用并行循环。我的特殊情况的代码是这样的:

      var path = require('path');
      var fs = require('fs');
      
      exports.browse2 = function(request, response) {
      getFolderContents(
              'C:\\Users\\AccountName\\folder1\\folder2\\folder3\\test\\',
              function(err, tree) {
                  if (err)
                      throw err;
                  response.send(tree);
              });
      };
      
      function getFolderContents(route, callback) {
      var branch = {};
      branch.title = path.basename(route);
      branch.folder = true;
      branch.children = [];
      
      fs.readdir(route, function(err, files) {
          if (err)
              return callback(err);
          var pending = files.length;
          if (!pending)
              return callback(null, branch);
          files.forEach(function(file) {
              var concatPath = path.join(route, file);
              fs.lstat(concatPath, function(err, stats) {
                  if (stats && stats.isDirectory()) {
                      getFolderContents(concatPath, function(err, res) {
                          branch.children.push(res);
                          if (!--pending)
                              callback(null, branch);
                      });
                  } else {
                      branch.children.push({
                          "title" : path.basename(file),
                          "path" : file
                      });
                      if (!--pending)
                          callback(null, branch);
                  }
              });
          });
      });
      }
      

    感谢用户“chjj”在此线程上回复了类似问题:node.js fs.readdir recursive directory search

    感谢用户“Dan Smolinske”将我引导至该主题。

    【讨论】:

    • 我花了 10 分钟来格式化这段代码。我认为系统不喜欢我的语法。也许版主可以解决这个问题?
    猜你喜欢
    • 2016-11-16
    • 2016-03-18
    • 2015-07-09
    • 1970-01-01
    • 2019-04-14
    • 2012-08-05
    • 2020-05-06
    • 2021-04-01
    相关资源
    最近更新 更多