【问题标题】:How can I use promises to get this code to work correctly?如何使用 Promise 让此代码正常工作?
【发布时间】:2019-10-02 02:01:07
【问题描述】:

在我的代码完成对文件夹层次结构的递归之后,我想使用then(),如下所示。

一切都很好,尤其是使用

  const fileNames = await fs.promises.readdir(dir);

  const stat = await fs.promises.stat(thing_path);

但是,递归部分我不知道如何正确实现

getFolderInfo(start).then((all_data)=>{
  console.log('Done recursing the directory');  
});

工作正常。

完整文件

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

// Configure & Initialize
let start = '_t/';
let depth = 1;
let counter = 0;
let total_size = 0;

// Definition
async function recurseFolders(dir, callback) {
  const fileNames = await fs.promises.readdir(dir);
  const listings = await Promise.all(
    fileNames.map(async (thing_name) => {
      const thing_path = path.join(dir, thing_name);
      const stat = await fs.promises.stat(thing_path);
      return {name: thing_name, path: thing_path, size: stat.size, isFolder: stat.isDirectory()};
    })
  );
  listings.forEach(iterate);
  function iterate (listing) {
    counter++;
    total_size += listing.size;
    listing.counter = counter;
    listing.total_size = total_size;
    callback(listing);
    if (listing.isFolder) {
      recurseFolders(listing.path, callback);
    }
  }
}

async function getFolderInfo (start) {
  await recurseFolders(start, (data) => {
    console.log(data);
  });
}

getFolderInfo(start).then((all_data)=>{
  console.log('Done recursing the directory');  
});

【问题讨论】:

  • 递归的recurseFolders 调用没有await;这是故意的吗?
  • 我在调用中添加了一个 await 并创建了函数iterate async,但它仍然没有所需的行为。
  • 这是节点代码有没有办法让它在stackoverflow上的浏览器中运行?
  • 观察到的行为是什么?顺便说一句,您现在没有填充 all_data
  • 控制台记录“完成递归目录”的地方应该完成递归目录。 all_data 只是它开始工作时的占位符。

标签: javascript node.js recursion promise


【解决方案1】:

如果您将 fs 工作放在自己的函数中,问题就会很好地解决。此函数在给定路径上运行stat,并为每个条目回答修改后的统计对象...

async function getStats(path) {
  const names = await fs.promises.readdir(path);
  let promises = names.map(async name => {
      const pathName = path.join(path, name)
      const stat = await fs.promises.stat(pathName);
      return { name: name, path: pathName, size: stat.size, isFolder: stat.isDirectory() };
  })
  return await Promise.all(promises)
}

现在,只需为给定路径调用 getStats,将回调应用到每个结果,然后在包含的目录上进行递归或什么都不做......

async function recurseFolders(path, callback) {
    const stats = await getStats(path)
    let promises = stats.map(async stat => {
        callback(stat)
        return await stat.isFolder ? recurseFolders(stat.path, callback) : Promise.resolve()
    })
    return await Promise.all(promises)
}

就是这样。

【讨论】:

    【解决方案2】:

    如果您不尝试将文件夹层次结构扁平化为列表,则可以简化此操作。我对您期望如何使用countertotal_size 做了一些假设。我也忽略了未使用的depth 参数。

    const fs = require('fs');
    const path = require('path');
    
    async function recurseFolders(folderPath) {
        const fileNames = await fs.promises.readdir(folderPath);
        const fileData = await Promise.all(
            fileNames.map(async (fileName) => {
                const filePath = path.join(folderPath, fileName);
                const fileStat = await fs.promises.stat(filePath);
                if (fileStat.isDirectory()) {
                    return recurseFolders(filePath);
                }
                return { 
                    name: fileName, 
                    path: filePath,
                    size: fileStat.size,
                    isFolder: false
                };
            })
        );
        const folder = {
            name: path.basename(folderPath),
            path: folderPath,
            files: fileData,
            isFolder: true,
            count: fileData.length,
            size: 0
        };
        return fileData.reduce((total, file) => {
            total.size += file.size;
            if (file.isFolder) {
                total.count += file.count;
            }
            return total;
        }, folder);
    }
    
    recurseFolders('some/path/to/folder').then((file) => {
        console.log(file);
    }).catch((err) => {
        process.exitCode = 1;
        console.error(err);
    });
    

    此实现将返回如下所示的数据结构:

    {
        "name": "demo",
        "path": "example/path/demo",
        "files": [
            {
                "name": "dir1",
                "path": "example/path/demo/dir1",
                "files": [
                    {
                        "name": "dir2",
                        "path": "example/path/demo/dir1/dir2",
                        "files": [
                            {
                                "name": "file3.txt",
                                "path": "example/path/demo/dir1/dir2/file3.txt",
                                "size": 7412,
                                "isFolder": false
                            }
                        ],
                        "isFolder": true,
                        "count": 1,
                        "size": 7412
                    },
                    {
                        "name": "file2.txt",
                        "path": "example/path/demo/dir1/file2.txt",
                        "size": 8364,
                        "isFolder": false
                    }
                ],
                "isFolder": true,
                "count": 3,
                "size": 15776
            },
            {
                "name": "file1.txt",
                "path": "example/path/demo/file1.txt",
                "size": 6870,
                "isFolder": false
            }
        ],
        "isFolder": true,
        "count": 5,
        "size": 22646
    }
    

    【讨论】:

      【解决方案3】:
      var fs = require('fs');
      var path = require('path');
      var getFolderInfo = function (dir, done) {
          var results = [];
          fs.readdir(dir, function (err, list) {
              if (err) return done(err);
              var pending = list.length;
              if (!pending) return done(null, results);
              list.forEach(function (file) {
                  file = path.resolve(dir, file);
                  fs.stat(file, function (err, stat) {
                      if (stat && stat.isDirectory()) {
                          getFolderInfo(file, function (err, res) {
                              results = results.concat(res);
                              if (!--pending) done(null, results);
                          });
                      } else {
                          results.push(file);
                          if (!--pending) done(null, results);
                      }
                  });
              });
          });
      };
      
      getFolderInfo('/home/username', function (err, results) {
          if (err) throw err;
          console.log(results);
      });
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-07-16
        • 1970-01-01
        • 2020-07-18
        • 1970-01-01
        • 1970-01-01
        • 2022-11-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多