简体   繁体   English

node.js异步函数是否在循环?

[英]node.js async function in loop?

I am having some problems with node.js. 我在使用node.js时遇到了一些问题。 What I'm trying to do is get an array of the directories in "./"+req.user.email and loop through them finding out their size and adding a table row to output, as you can see in the code. 我想做的是在“ ./"+req.user.email中获取目录数组,并遍历它们以找出它们的大小并在输出中添加一个表行,如代码所示。 At the end I wan't to send all the table rows using res.send(). 最后,我不想使用res.send()发送所有表行。

However the only output I am getting is: 但是我得到的唯一输出是:

<tr></tr>

for each file in the array. 对于数组中的每个文件。 It seems that the forEach function is not waiting for readSizeRecursive at all. 似乎forEach函数根本没有等待readSizeRecursive。 The readSizeRecursive function is asynchronous, and I believe that is what's causing the problem, but I don't know how I can fix this. readSizeRecursive函数是异步的,我认为这是导致问题的原因,但我不知道如何解决此问题。

Any help would be greatly appreciated, I have included the readSizeRecursive function too. 任何帮助将不胜感激,我也包括readSizeRecursive函数。 Thank you! 谢谢!

  var output = "";
  fs.readdir("./" + req.user.email, function (err, files) {
    files.forEach(function(file){
      output += "<tr>";
      readSizeRecursive("./"+req.user.email+"/"+file, function (err, total){
        output += '<td>' + file + '</td><td>' + total + '</td>';
      });
      output += "</tr>"
    });
    res.send(output)
  });

readSizeRecursive() : readSizeRecursive():

// Function to find the size of a directory
function readSizeRecursive(item, cb) {
  fs.lstat(item, function(err, stats) {
    var total = stats.size;

    if (!err && stats.isDirectory()) {
      fs.readdir(item, function(err, list) {
        async.forEach(
          list,
          function(diritem, callback) {
            readSizeRecursive(path.join(item, diritem), function(err, size) {
              total += size;
              callback(err);
            }); 
          },  
          function(err) {
            cb(err, total);
          }   
        );  
      }); 
    }   
    else {
      cb(err, total);
    }   
  }); 
}

Please use the async module for this kind of pattern. 请为这种模式使用异步模块。 Using async.each will allow you to compute the size for each folder asynchronously, and then return the sizes once you're done computing everything individually. 使用async.each将允许您异步计算每个文件夹的大小,然后在分别计算完所有内容后返回大小。

var output = [];

fs.readdir('./' + req.user.email, function (err, files) {
  async.each(compute, report);
});

function compute (file, done) {
  // calculate size, then callback to signal completion
  // produce a result like below, then invoke done()
  var obj = { files: [
    { name: file, size: size },
    { name: file, size: size },
    { name: file, size: size }
  ]};
  output.push(obj);
  done();
}

// doesn't need to be this awful
function format (list) {
  var result = [];

  list.forEach(function (item) {
    var description = item.files.map(function (file) {
      return util.format('<td>%s</td><td>%s</td>', file.name, file.size);
    });
    result.push(description);
  });

  result.unshift('<tr>');
  result.push('</tr>');
  return result.join('</tr><tr>');
}

function report (err) {
  if (err) { return next(err); }

  var result = format(output);
  res.send(result);
}

This way you can easily swap out the different pieces of functionality, changing the formatting without altering the computing of the file size tree, for example. 这样,您可以轻松地交换不同的功能,例如在不更改文件大小树的计算的情况下更改格式。

Your main issue was control flow. 您的主要问题是控制流程。 You return with res.send while you are asynchronously looping and figuring out the sizes. 在异步循环并确定大小时,将返回res.send

var fs = require ("fs");

var createTableContent = function (p, cb){
    var read = function (p, cb){
        //Prevent recursion if error
        if (err) return cb ();

        fs.stat (p, function (error, stats){
            if (error){
                err = error;
                return cb ();
            }

            if (stats.isDirectory ()){
                var dirSize = 0;

                fs.readdir (p, function (error, entries){
                    if (error){
                        err = error;
                        return cb ();
                    }

                    var pending = entries.length;
                    //Empty dir
                    if (!pending) return cb (0);

                    entries.forEach (function (entry){
                        read (p + "/" + entry, function (entrySize){
                            dirSize += entrySize;
                            if (!--pending) return cb (dirSize);
                        });
                    });
                });
            }else{
                cb (stats.size);
            }
        });
    };

    //A lot of errors can be produced, return only the first one
    var err = null;

    //Suppose p is a dir
    fs.readdir (p, function (error, entries){
        if (error) return cb (error);

        var content = "";
        var pending = entries.length;
        if (!pending) return cb (null, content);

        entries.forEach (function (entry){
            read (p + "/" + entry, function (totalSize){
                if (err) return cb (err);
                content += "<tr><td>" + entry + "</td><td>" + totalSize + "</td></tr>";
                if (!--pending){
                    //End
                    cb (null, content);
                }
            });
        });
    });
};

//Here goes the "email" path
createTableContent (".", function (error, content){
    if (error) return console.error (error);

    console.log (content);
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM