我尝试用highland.js
编写一个程序来下载几个文件,解压缩并解析成对象,然后通过flatMap
将对象流合并到一个流中并打印出来。
function download(url) {
return _(request(url))
.through(zlib.createGunzip())
.errors((err) => console.log('Error in gunzip', err))
.through(toObjParser)
.errors((err) => console.log('Error in OsmToObj', err));
}
const urlList = ['url_1', 'url_2', 'url_3'];
_(urlList)
.flatMap(download)
.each(console.log);
当所有网址都有效时,它可以正常工作。如果URL无效,则没有下载文件,则gunzip报告错误。我怀疑发生错误时流会关闭。我希望flatMap
将继续使用其他流,但程序不会下载其他文件,也没有打印出来。
在流中处理错误的正确方法是什么,以及在一个流出错后如何使flatMap
不停止?
在命令式编程中,我可以添加调试日志来跟踪错误发生的位置。如何调试流代码?
PS。 toObjParser
是节点转换流。它需要一个可读的OSM XML流,并输出与Overpass OSM JSON兼容的对象流。见https://www.npmjs.com/package/osm2obj
2017-12-19更新:
我试图在push
中致电errors
,因为@amsross建议。为了验证push
是否真的有效,我推送了一个XML文档,它由解析器解析,我从输出中看到它。但是,流仍然停止,并且未下载url_3。
function download(url) {
console.log('download', url);
return _(request(url))
.through(zlib.createGunzip())
.errors((err, push) => {
console.log('Error in gunzip', err);
push(null, Buffer.from(`<?xml version='1.0' encoding='UTF-8'?>
<osmChange version="0.6">
<delete>
<node id="1" version="2" timestamp="2008-10-15T10:06:55Z" uid="5553" user="foo" changeset="1" lat="30.2719406" lon="120.1663723"/>
</delete>
</osmChange>`));
})
.through(new OsmToObj())
.errors((err) => console.log('Error in OsmToObj', err));
}
const urlList = ['url_1_correct', 'url_2_wrong', 'url_3_correct'];
_(urlList)
.flatMap(download)
.each(console.log);
答案 0 :(得分:0)
2017年12月19日更新:
好的,所以我不能给你一个好的为什么这个,但我可以告诉你,从download
sequence
中消费的流量转换为{{1}将它们放在一起可能会给你你想要的结果。不幸的是(或不是?),您将不再以任何规定的顺序获得结果。
merge
更新12/03/2017:
当在流上遇到错误时,它将结束该流。为避免这种情况,您需要处理错误。您当前正在使用const request = require('request')
const zlib = require('zlib')
const h = require('highland')
// just so you can see there isn't some sort of race
const rnd = (min, max) => Math.floor((Math.random() * (max - min))) + min
const delay = ms => x => h(push => setTimeout(() => {
push(null, x)
push(null, h.nil)
}, ms))
const download = url => h(request(url))
.flatMap(delay(rnd(0, 2000)))
.through(zlib.createGunzip())
h(['urlh1hcorrect', 'urlh2hwrong', 'urlh3hcorrect'])
.map(download).merge()
// vs .flatMap(download) or .map(download).sequence()
.errors(err => h.log(err))
.each(h.log)
报告错误,但未对其进行处理。你可以这样做,继续前进到流中的下一个值:
errors
原件:
如果不知道.errors((err, push) => {
console.log(err)
push(null) // push no error forward
})
的输入和输出类型,就很难回答。
由于toObjParser
将值流传递给提供的函数并期望返回一个值流,因此您的问题可能位于through
,其签名为toObjParser
或{{ 1}},其中错误发生在内部流上,在消耗之前不会发出任何错误。
Stream -> Object
的输出是什么?如果它正在记录流,那很可能是你的问题。