【问题标题】:Is there a better way to write this recursing method in typescript有没有更好的方法在打字稿中编写这种递归方法
【发布时间】:2020-04-03 15:02:03
【问题描述】:

我正在尝试编写一种方法来查找文件夹中的所有文件,包括子文件夹。使用fs.readdirSync 编写非常简单,但我正在尝试编写一个不会阻塞的版本。 (即使用fs.readdir)。

我有一个可用的版本,但它并不漂亮。对节点有更多经验的人可以看看是否有更好的方法来编写这个?我可以在我的代码库中看到可以应用此模式的其他几个地方,所以如果有一个更简洁的版本会很好!

  private static findFilesFromFolder(folder: string): Promise<string[]> {
    let lstat = util.promisify(fs.lstat)
    let readdir = util.promisify(fs.readdir)

    // Read the initial folder
    let files = readdir(folder)

      // Join the folder name to the file name to make it absolute
      .then(files => files.map(file => path.join(folder, file)))

      // Get the stats for each file (also as a promise)
      .then(files =>
        Promise.all(files.map(file =>
          lstat(file).then(stats => { return { file: file, stats: stats } })
        ))
      )

      // If the file is a folder, recurse. Otherwise just return the file itself.
      .then(info =>
        Promise.all(info.map(info => {
          if (info.stats.isDirectory()) {
            return this.findFilesFromFolder(info.file)
          } else {
            return Promise.resolve([info.file])
          }
        }
      )))

      // Do sume munging of the types - convert Promise<string[][]> to Promise<string[]>
    .then(nested => Array.prototype.concat.apply([], nested) as string[])

    return files
  }

【问题讨论】:

  • 当您不在任何地方使用await 时,不要将其设为async 函数。
  • @Bergi 已删除。
  • 使用await,会使递归代码非常接近同步版本
  • @TitianCernicova-Dragomir 您应该添加它作为答案 - 我在写这篇文章时完全忘记了使用 await 不会阻塞,而是在引擎盖下使用 Promise。没错,现在干净多了!
  • @deanWombourne 我正在研究答案,但转换需要一些时间????我看到 Bergi 打败了我 :)

标签: node.js typescript recursion promise


【解决方案1】:

我会做一些事情来让这个更干净:

  • 将递归基本情况从循环内移到顶层
  • 使用async/await语法
  • 使用const 而不是let

同时将promisify 调用放在你所在的位置importing fs

const lstat = util.promisify(fs.lstat)
const readdir = util.promisify(fs.readdir)

…
private static async findFilesFromPath(folder: string): Promise<string[]> {
  const stats = await lstat(folder);
  // If the file is a folder, recurse. Otherwise just return the file itself.
  if (stats.isDirectory()) {
    // Read the initial folder
    const files = await readdir(folder);
    // Join the folder name to the file name to make it absolute
    const paths = files.map(file => path.join(folder, file))
    const nested = await Promise.all(paths.map(p => this.findFilesFromPath(p)))
    // Do sume munging of the types - convert string[][] string[]
    return Array.prototype.concat.apply([], nested) as string[];
  } else {
    return [folder];
  }
}

【讨论】:

  • 使用 await 是我错过的关键 - 我(尴尬地)忘记了 await 不会阻塞,它只是 Promise 而已。不过,您为什么要将 promisify 作为全局变量而不是仅在此方法中使用(我不会在其他任何地方使用它们,否则答案很明显!)?
  • @deanWombourne 这样promisify 只被调用一次,而不是通过每个方法调用。
  • 哦,当然,它是递归的!真是小学生的错误,我今天过得不好!
  • 不仅仅是因为递归,还因为你从外部多次调用你的方法。诚然,promisify 确实缓存了它的结果,所以当你把它放在里面时它不会成​​为性能问题,但我仍然认为它更干净——而且它还可以在模块的其他地方重用,即使你不需要
  • 哈,我们在这方面有所不同——在需要之前我不会将它们移出(不过,由于递归,我确实需要,哎呀)。有趣的承诺缓存 - 我不知道。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-07-18
  • 2020-03-16
  • 1970-01-01
  • 2014-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多