首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Highland.js中的嵌套流操作

Highland.js中的嵌套流操作
EN

Stack Overflow用户
提问于 2014-12-31 12:37:07
回答 1查看 1.1K关注 0票数 1

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

我想:-

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

我正在尝试使用streams和highland.js来完成这个任务。

我无法处理每个目录中所有文件的流。

代码语言:javascript
复制
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}
EN

回答 1

Stack Overflow用户

发布于 2015-07-09 10:35:36

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

另外,Highland方法很懒:只有在绝对需要数据时才应该调用eachtoArray

异步映射流的标准方法是flatMap。它类似于map,但是您给它的函数应该返回一个流。从flatMap获得的流是所有返回流的连接。由于新流按顺序依赖于所有旧流,因此可以用来对异步进程进行排序。

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

代码语言:javascript
复制
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类型的事物和包含bs的返回流的函数,并返回一个包含b的流。集合类型(例如流和数组)实现flatMap作为连接返回的集合的标准。

代码语言:javascript
复制
h(readdirp root: root, depth: 0, entryType: 'directories')

假设这里有Stream Directory类型。filter不会更改类型,所以flatMap将是Stream Directory → (Directory → Stream b) → Stream b。我们将看到函数返回的内容:

代码语言:javascript
复制
h(readdirp root: dir.fullPath, depth: 0, entryType: 'files', fileFilter: '!.DS_Store')

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

代码语言:javascript
复制
h(fs.createReadStream file.name)

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

请注意,由于Highland的懒惰,这实际上不会启动任何流或处理。您需要使用eachtoArray来导致thunk并启动管道。在each中,回调将与对象一起调用。取决于您想要对这些注释做些什么,最好再使用一些flatMap (例如,如果您将它们写到一个文件中)。

我不是有意写文章的。希望这能有所帮助。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27721268

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档