我有一个来自readdirp
模块的目录流。
我想: -
README.*
)搜索文件#
我正在尝试使用流和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}
答案 0 :(得分:4)
最好将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
的函数的函数并返回包含b
s的流,并返回包含b
s的流。它是集合类型(例如流和数组)的标准,用于将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
函数返回的内容。升级,第二个b
中的flatMap
是对象,因此第一个flatMap
的函数也返回对象的流,因此整个流是{{1} }。
请注意,由于Highland的懒惰,这实际上并不会启动任何流媒体或处理。您需要使用Stream {name : String, comment : String}
或each
来生成toArray
并启动管道。在thunk
中,将使用您的对象调用回调。根据您对评论的要求,最好each
一些(例如,如果您将它们写入文件)。
好吧,我不是故意写一篇文章。希望这会有所帮助。