【问题标题】:Traverse directory tree in node.js using RxJs使用 RxJs 遍历 node.js 中的目录树
【发布时间】:2016-04-01 22:46:39
【问题描述】:

我正在尝试使用 RxJs 和 node.js 遍历目录树。

我想出了可行的解决方案:

const filesInDir = Rx.Observable.fromNodeCallback(fs.readdir)
const statFile = Rx.Observable.fromNodeCallback(fs.stat)

const listFiles = (prefix, dir = '') => {
    const file$ = filesInDir(`${prefix}/${dir}`)
        .flatMap(file => file)
        .filter(file => !file.startsWith('.'))
    const isDir$ = file$
        .map(file => statFile(`${prefix}/${dir}/${file}`))
        .flatMap(file => file)
        .map(file => file.isDirectory())
    return file$
        .zip(isDir$, (file, isDir) => {return {file, isDir}})
        .map(f => {
            if (f.isDir) {
                return listFiles(prefix, `${dir}/${f.file}`)
            }
            return Rx.Observable.return(`${dir}/${f.file}`)
        })
        .flatMap(file => file)
}

listFiles('public')
    .toArray()
    .subscribe(list => {
        console.log(list)
    })

问题:

  1. 有没有更高效/更简洁的方式来.map 使用异步操作?
  2. .zip 部分的相同问题

【问题讨论】:

    标签: javascript node.js rxjs


    【解决方案1】:

    好问题。

    我认为你可以做一些事情来优化这个查询。

    首先,我们可以将map 运算符和.flatMap(file => file) 更改为仅一个平面地图。微小的改进,但会运行更少的代码。

    const file$ = filesInDir(`${prefix}/${dir}`)
        .flatMap(file => file)
        .filter(file => !file.startsWith('.'))
    const isDir$ = file$
        .flatMap(file => statFile(`${prefix}/${dir}/${file}`))
        .map(file => file.isDirectory())
    return file$
        .zip(isDir$, (file, isDir) => {return {file, isDir}})
        .flatMap(f => {
            if (f.isDir) {
                return listFiles(prefix, `${dir}/${f.file}`)
            }
            return Rx.Observable.return(`${dir}/${f.file}`)
        })
    

    主要的改进是我相信您实际上两次访问了文件系统。 filesInDir 可观察序列不是热/缓存序列。 如果是这样,目录树的递归遍历将不起作用。 考虑到这一点,您调用它一次来获取所有文件,然后再次调用它来执行isDirectory 检查。 这会引入潜在的性能成本和错误。 您假设当您点击磁盘时,返回的文件序列将始终保持相同的顺序。 即使我们忽略一秒钟,该磁盘也是可变的,它可能在你的带领下发生变化。 您可以保证在异步世界中,序列将以相同的顺序返回。 在我的机器(Windows 10)上,序列大多以相同的顺序返回。 但是,如果树足够深(例如来自 _C:_),我每次都会遇到不匹配的情况。

    无论如何,性能修复也是错误修复。 我们可以只做一次,而不是每次都从文件系统中重新读取。 将 statFile() 调用移动到 flatMap 中,该调用还将结果与传递给 statFile 的文件的闭包进行映射

    const listFiles = (prefix, dir) => {
        return file$ = filesInDir(`${prefix}/${dir}`)
            .flatMap(file => file)
            .filter(file => !file.startsWith('.'))
            .flatMap(file => statFile(`${prefix}/${dir}/${file}`)
                        .map( sf => {return {file, isDir: sf.isDirectory()}}) )
            .flatMap(f => {
                if (f.isDir) {
                    return listFiles(prefix, `${dir}/${f.file}`)
                }
                return Rx.Observable.return(`${dir}/${f.file}`)
            })
    }
    

    这还具有删除Zip 子句的好处,因为我们不再尝试使用两个序列。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-10-25
      • 1970-01-01
      • 2014-10-05
      • 1970-01-01
      • 2021-01-27
      • 1970-01-01
      • 2016-09-09
      • 2018-01-13
      相关资源
      最近更新 更多