有没有更好的方法在打字稿中编写这种递归方法

Posted

技术标签:

【中文标题】有没有更好的方法在打字稿中编写这种递归方法【英文标题】: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 打败了我 :) 【参考方案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 确实缓存了它的结果,所以当你把它放在里面时它不会成​​为性能问题,但我仍然认为它更干净——而且它还可以在模块的其他地方重用,即使你不需要 哈,我们在这方面有所不同——在需要之前我不会将它们移出(不过,由于递归,我确实需要,哎呀)。有趣的承诺缓存 - 我不知道。

以上是关于有没有更好的方法在打字稿中编写这种递归方法的主要内容,如果未能解决你的问题,请参考以下文章

vscode自动完成不适用于打字稿中的方法

vscode自动完成不适用于打字稿中的方法

有没有更好的方法来退出递归?

!对象方法后打字稿中的运算符

!对象方法后打字稿中的运算符

在nodejs和打字稿中使用变量到静态方法