高地.js的嵌套溪流作业



>我有来自readdirp模块的目录流。

我想:-

  • 使用正则表达式搜索文件(例如 README.* ) 在每个目录中
  • 读取该文件中不以#开头的第一行
  • 打印出每个目录和目录中自述文件的第一非标题行。

我正在尝试使用溪流和高原.js来做到这一点。

我被困在尝试处理每个目录中所有文件的流时。

h = require 'highland'
dirStream = readdirp root: root, depth: 0, entryType: 'directories'
dirStream = h(dirStream)
  .filter (entry) -> entry.stat.isDirectory()
  .map (entry) ->
    # Search all files in the directory for README.
    fileStream = readdirp root: entry.fullPath, depth: 0, entryType: 'files', fileFilter: '!.DS_Store'
    fileStream = h(fileStream).filter (entry) -> /README..*/.test entry.name
    fileStream.each (file) ->
      readmeStream = fs.createReadStream file
      _(readmeStream)
        .split()
        .takeUntil (line) -> not line.startsWith '#' and line isnt ''
        .last(1)
        .toArray (comment) ->
          # TODO: How do I access `comment` asynchronously to include in the return value of the map?
    return {name: entry.name, comment: comment}

最好将高地流视为不可变的,并且像filtermap这样的操作返回依赖于旧流的新流,而不是对旧流的修改。

此外,Highland 方法也很懒惰:您应该仅在现在绝对需要数据时才调用 eachtoArray

异步映射流的标准方法是flatMap 。这就像map,但你给它的函数应该返回一个流。从flatMap获取的流是所有返回流的串联。由于新流按顺序依赖于所有旧流,因此可用于对异步过程进行排序。

我会将您的示例修改为以下内容(澄清了一些变量名称):

h = require 'highland'
readmeStream = h(readdirp root: root, depth: 0, entryType: 'directories')
  .filter (dir) -> dir.stat.isDirectory()
  .flatMap (dir) ->
    # Search all files in the directory for README.
    h(readdirp root: dir.fullPath, depth: 0, entryType: 'files', fileFilter: '!.DS_Store')
    .filter (file) -> /README..*/.test file.name
    .flatMap (file) ->
      h(fs.createReadStream file.name)
        .split()
        .takeUntil (line) -> not line.startsWith '#' and line isnt ''
        .last(1)
        .map (comment) -> {name: file.name, comment}

让我们浏览一下此代码中的类型。首先,请注意flatMap具有类型(在哈斯克利符号中)Stream a → (a → Stream b) → Stream b,即它接受一个包含一些类型a的事物的流,以及一个期望类型为a的事物并返回包含b s的流的函数,并返回一个包含b s的流。集合类型(如流和数组)的标准是将flatMap实现为连接返回的集合。

h(readdirp root: root, depth: 0, entryType: 'directories')

假设这有类型 Stream Directory .filter不会更改类型,因此flatMapStream Directory → (Directory → Stream b) → Stream b。我们将看到函数返回的内容:

h(readdirp root: dir.fullPath, depth: 0, entryType: 'files', fileFilter: '!.DS_Store')

称之为Stream File,所以第二个flatMapStream File → (File → Stream b) → Stream b

h(fs.createReadStream file.name)

这是一个Stream String. splittakeUntillast不会改变这一点,那么map会怎么做呢? mapflatMap非常相似:它的类型是 Stream a → (a → b) → Stream b 。在本例中,a Stringb是对象类型{name : String, comment : String}。然后map返回该对象的流,这是整个flatMap函数返回的内容。向上一步,第二个flatMap中的b是对象,所以第一个flatMap的函数也返回对象的一个流,所以整个流就是一个Stream {name : String, comment : String}

请注意,由于Highland的懒惰,这实际上并没有启动任何流式传输或处理。需要使用eachtoArray来引发thunk并启动管道。在 each 中,回调将使用您的对象调用。根据您要对注释执行的操作,最好再flatMap一些(例如,如果要将它们写入文件)。

好吧,我不是故意写一篇文章。希望这有帮助。

相关内容

  • 没有找到相关文章

最新更新