繁体   English   中英

Highland.js中的嵌套流操作

[英]Nested stream operations in Highland.js

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

我想要:-

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

我正在尝试使用stream和highland.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}

最好将Highland流视为不可变的,并且像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具有类型(用Haskellish表示法) Stream a → (a → Stream b) → Stream b ,即,它接受包含a类型a某些东西的流,以及一个期望a类型a东西并返回包含b流的函数。 s,并返回包含b的流。 集合类型(例如流和数组)的标准是实现flatMap串联返回的集合。

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

假设它的类型为Stream Directory filter器不会更改类型,因此flatMap将是Stream 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 在这种情况下, aStringb为对象类型{name : String, comment : String} 然后map返回该对象的流,这是整个flatMap函数返回的内容。 向上移动,第二个flatMap中的b是对象,因此第一个flatMap的函数还返回对象的流,因此整个流是Stream {name : String, comment : String}

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

好吧,我不是要写论文。 希望这可以帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM