[英]Nested stream operations in Highland.js
我有来自readdirp
模块的目录流。
我想要:-
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流视为不可变的,并且像filter
和map
这样的操作会返回依赖于旧流而不是修改旧流的新流。
同样,Highland方法是惰性的:仅当您现在绝对需要数据时,才应调用each
或toArray
。
异步映射流的标准方法是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
,因此第二个flatMap
是Stream File → (File → Stream b) → Stream b
。
h(fs.createReadStream file.name)
这是一个Stream String
。 split
, takeUntil
和last
都不会改变它,那么map
做什么? map
与flatMap
非常相似:其类型为Stream a → (a → b) → Stream b
。 在这种情况下, a
为String
, b
为对象类型{name : String, comment : String}
。 然后map
返回该对象的流,这是整个flatMap
函数返回的内容。 向上移动,第二个flatMap
中的b
是对象,因此第一个flatMap
的函数还返回对象的流,因此整个流是Stream {name : String, comment : String}
。
请注意,由于Highland的懒惰,实际上并没有启动任何流或处理。 您需要使用each
或toArray
引起重thunk
并启动管道。 在each
,回调将与您的对象一起调用。 根据您要对注释执行的操作,最好再进行flatMap
(例如,如果您将其写入文件中)。
好吧,我不是要写论文。 希望这可以帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.