节点.js循环中的异步函数

node.js async function in loop?

本文关键字:异步 函数 js 循环 节点      更新时间:2023-09-26

我在使用node.js时遇到了一些问题。 我试图做的是获取"./"+req.user.email 中的目录数组,并遍历它们以找出它们的大小并添加一个表行进行输出,如您在代码中看到的那样。 最后,我不想使用 res.send() 发送所有表行。

但是,我得到的唯一输出是:

<tr></tr>

对于数组中的每个文件。似乎forEach函数根本没有等待readSizeRecursive。 readSizeRecursive 函数是异步的,我相信这就是导致问题的原因,但我不知道如何解决这个问题。

任何帮助将不胜感激,我也包含了readSizeRecursive函数。谢谢!

  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() :

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

请使用异步模块来实现这种模式。使用 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);
}

通过这种方式,您可以轻松交换不同的功能,例如,在不更改文件大小树计算的情况下更改格式。

您的主要问题是控制流。在异步循环和计算大小时,您返回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);
});