简体   繁体   English

当一个流有错误时,为什么flatMap没有输出?

[英]Why flatMap has no output when one stream has error?

I tried to write a program with highland.js to download several files, unzip them and parse into objects, then merge object streams into one stream by flatMap and print out. 我试图用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);

When all URLs are valid, it works fine. 当所有URL有效时,它可以正常工作。 If a URL is invalid there is no file downloaded, then gunzip reports error. 如果URL无效,则没有文件下载,gunzip报告错误。 I suspect that the stream closes when error occurs. 我怀疑发生错误时流将关闭。 I expect that flatMap will continue with other streams, however the program doesn't download other files and there is nothing printed out. 我希望flatMap将继续使用其他流,但是该程序不会下载其他文件,并且没有打印出任何内容。

What's the correct way to handle error in stream and how to make flatMap not stop after one stream has error? 处理流中错误的正确方法是什么?如何在一个流出现错误后使flatMap不停止?

In imperative programming, I can add debug logs to trace where error happens. 在命令式编程中,我可以添加调试日志以跟踪发生错误的位置。 How to debug streaming code? 如何调试流代码?

PS. PS。 toObjParser is a Node Transform Stream. toObjParser是节点转换流。 It takes a readable stream of OSM XML and outputs a stream of objects compatible with Overpass OSM JSON. 它采用可读的OSM XML流,并输出与Overpass OSM JSON兼容的对象流。 See https://www.npmjs.com/package/osm2obj 参见https://www.npmjs.com/package/osm2obj

2017-12-19 update: 2017年12月19日更新:

I tried to call push in errors as @amsross suggested. 我尝试按照@amsross的建议调用push errors To verify if push really works, I pushed a XML document and it was parsed by following parser and I saw it from output. 为了验证push是否确实有效,我推送了一个XML文档,并通过跟随解析器对其进行了解析,并从输出中看到了它。 However, stream still stopped and url_3 was not downloaded. 但是,流仍然停止并且未下载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);

Update 12/19/2017: Ok, so I can't give you a good why on this, but I can tell you that switching from consuming the streams resulting from download in sequence to merge 'ing them together will probably give you the result you're after. 2017年12月19日更新:好的,所以我不能很好地解释为什么这样做,但是我可以告诉你,从使用按sequence download产生的流切换到merge它们merge在一起可能会给你结果你在追。 Unfortunately (or not?), you will no longer be getting the results back in any prescribed order. 不幸的是(或不是?),您将不再以任何规定的顺序取回结果。

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)

Update 12/03/2017: When an error is encountered on the stream, it ends that stream. 更新12/03/2017:当流上遇到错误时,它将终止该流。 To avoid this, you need to handle the error. 为了避免这种情况,您需要处理该错误。 You are currently using errors to report the error, but not handle it. 您当前正在使用errors来报告错误,但没有处理。 You can do something like this to move on to the next value in the stream: 您可以执行以下操作以继续处理流中的下一个值:

.errors((err, push) => {
  console.log(err)
  push(null) // push no error forward
})

Original: It's difficult to answer without knowing the input and output types of toObjParser are. 原始语言:不知道toObjParser的输入和输出类型很难回答。

Because through passes a stream of values to the provided function and expects a stream of values in return, your issue may reside in toObjParser having a signature like Stream -> Object , or Stream -> Stream Object , where the errors are occurring on the inner stream, which will not emit any errors until it is consumed. 因为through将值toObjParser提供的函数并期望返回值流,所以您的问题可能驻留在具有签名的toObjParser ,该签名类似于toObjParser Stream -> ObjecttoObjParser Stream -> Stream Object ,其中错误发生在内部流,直到被消耗掉,它不会发出任何错误。

What is the output of .each(console.log) ? .each(console.log)的输出是什么? If it is logging a stream, that is most likely your problem. 如果它正在记录流,则很可能是您的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM