Node.js Highland.js中的嵌套流操作

Node.js Highland.js中的嵌套流操作,node.js,stream,highland.js,Node.js,Stream,Highland.js,我有一个来自readdirp模块的目录流 我想:- 在每个目录中使用正则表达式(例如,README.*)搜索文件 读取该文件中不以#开头的第一行 打印出每个目录以及目录中自述文件的第一个非标题行 我正在尝试使用流和 我一直在试图处理每个目录中的所有文件流 h = require 'highland' dirStream = readdirp root: root, depth: 0, entryType: 'directories' dirStream = h(dirStream)

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

我想:-

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

我一直在试图处理每个目录中的所有文件流

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}

<> P> >最好将高地流视为不可变的,如<代码>过滤器> /COD>和<代码> MAP>代码>返回依赖于旧流的新流,而不是修改旧流。

另外,Highland方法是懒惰的:当您现在绝对需要数据时,您应该只调用
每个
到阵列

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

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

让我们浏览一下代码中的类型。首先,请注意
flatMap
具有类型(在Haskellish表示法中)
流a→ (一)→ 溪流(b)→ 流b
,即,它接受一个包含
a
类型某些内容的流,以及一个期望
a
类型内容并返回包含
b
s的流的函数,并返回一个包含
b
s的流。将
flatMap
实现为连接返回的集合是集合类型(如流和数组)的标准

h(readdirp root: root, depth: 0, entryType: 'directories')
假设它具有类型
流目录
filter
不会更改类型,因此
flatMap
将是
Stream目录→ (目录→ 溪流(b)→ 流b
。我们将看到函数返回的内容:

h(readdirp root: dir.fullPath, depth: 0, entryType: 'files', fileFilter: '!.DS_Store')
将其称为
流文件
,因此第二个
平面图
流文件→ (档案→ 溪流(b)→ 流b

h(fs.createReadStream file.name)
这是一个
流字符串
<代码>拆分,
直到
最后一次
都不改变,那么
映射
做什么呢
map
flatMap
非常相似:它的类型是
流a→ (一)→ (b)→ 流b
。在这种情况下,
a
String
b
是一种对象类型
{name:String,comment:String}
。然后
map
返回该对象的流,这是整个
flatMap
函数返回的。向上一步,第二个
flatMap
中的
b
是对象,因此第一个
flatMap
函数也返回对象流,因此整个流是
流{name:String,comment:String}

注意,由于Highland的懒惰,这实际上不会启动任何流或处理。您需要使用
each
toArray
来引起
thunk
并启动管道。在每个中,将使用对象调用回调。根据您希望对注释执行的操作,最好再执行一些
flatMap
(例如,如果您正在将注释写入文件)


嗯,我不是有意写一篇文章的。希望这有帮助。

< P> >最好将高地流视为不可变的,操作如<代码>过滤器< /COD>和<代码> MAP>代码>返回依赖于旧流的新流,而不是对旧流的修改。

另外,Highland方法是懒惰的:当您现在绝对需要数据时,您应该只调用
每个
到阵列

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

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

让我们浏览一下代码中的类型。首先,请注意
flatMap
具有类型(在Haskellish表示法中)
流a→ (一)→ 溪流(b)→ 流b
,即,它接受一个包含
a
类型某些内容的流,以及一个期望
a
类型内容并返回包含
b
s的流的函数,并返回一个包含
b
s的流。将
flatMap
实现为连接返回的集合是集合类型(如流和数组)的标准

h(readdirp root: root, depth: 0, entryType: 'directories')
假设它具有类型
流目录
filter
不会更改类型,因此
flatMap
将是
Stream目录→ (目录→ 溪流(b)→ 流b
。我们将看到函数返回的内容:

h(readdirp root: dir.fullPath, depth: 0, entryType: 'files', fileFilter: '!.DS_Store')
将其称为
流文件
,因此第二个
平面图
流文件→ (档案→ 溪流(b)→ 流b

h(fs.createReadStream file.name)
这是一个
流字符串
<代码>拆分,
直到
最后一次
都不改变,那么
映射
做什么呢
map
flatMap
非常相似:它的类型是
流a→ (一)→ (b)→ 流b
。在这种情况下,
a
String
b
是一种对象类型
{name:String,comment:String}
。然后
map
返回该对象的流,这是整个
flatMap
函数返回的。向上,第二个
flatMap
中的
b
是对象,因此f