将节点流转换为Rx.js Observables

时间:2016-09-29 01:50:47

标签: javascript node.js reactive-programming rxjs

我正在努力将Node流转换为Rxjs Observables。

当我尝试1个URL时,流式传输本身效果很好。但是,当我尝试在URLS数组上映射相同的函数时,我会收到错误。

我正在使用Rx.Node将流转换为Observable。

这就是我目前正在尝试

// data_array is an array of 10 urls that I'm scraping data from. 
let parentStream = Rx.Observable.from(data_array);

parentStream.map(createStream).subscribe(x => console.log(x), (e)=> console.log('Error', e), console.log('Complete'));

function createStream(url){
  return RxNode.fromStream(x(url, '#centercol ul li', [{name: 'a', link: 'a@href'}]).write().pipe(JSONStream.parse('*')))
}

但这是输出 X 10(data_array中的URL数量)

RefCountObservable {
 source:
  ConnectableObservable {
   source: AnonymousObservable { source: undefined, __subscribe: [Function] },
 _connection: null,
 _source: AnonymousObservable { source: [Object], __subscribe: [Function: subscribe] },
 _subject:
  Subject {
    isDisposed: false,
    isStopped: false,
    observers: [],
    hasError: false } },
_count: 0,
_connectableSubscription: null }

我首先想到flatMap会起作用,因为它会在一个可观察的文本中展平observable ....但是当我尝试flatMap时,我得到了这个:

Complete
Error TypeError: unknown type returned

但是,如果我这样做:

这适用于1个网址,但我无法在一个流中捕获data_array中的所有网址。

let stream = RxNode.fromStream(x(url, '#centercol ul li', [{name: 'a', link: 'a@href'}]).write().pipe(JSONStream.parse('*')))

stream.subscribe(x => console.log(x), (e)=> console.log('Error', e), console.log('Complete'))

我觉得我误解了一些东西,不仅因为它清除不适用于多个URL,而且即使它在第二个例子中起作用....在所有数据进入之前我先得到'完成'。

显然,我误解了一些事情。任何帮助都会很精彩。感谢。

* UPDATE *

我尝试了不同的路径,但是不使用节点流。节点流是理想的,所以仍然希望使上面的示例工作。

我接下来使用的方法是在我的网络抓取功能周围包含一个承诺,即下面的 scrape 。这是有效的,但结果是十个巨大的数组,每个数组都有来自每个URL的所有数据。我真正想要的是一个对象流,我可以在数据对象通过时组成一系列转换。

这是不同的,但工作方法:

let parentStream = Rx.Observable.from(data_array);

parentStream.map(url => {
    return Rx.Observable.defer(() => {
        return scrape(url, '#centercol ul li', [{name: 'a', link: 'a@href'}]);
    })
})
    .concatAll()
    .subscribe(x => console.log(x), (e)=> console.log('Error', e), console.log('Complete'));

function scrape(url, selector, scope) {
    return new Promise(
        (resolve, reject) => x(
            url,
            selector,
            scope
        )((error, result) => error != null ? reject(error) : resolve(result))
    );
}

1 个答案:

答案 0 :(得分:1)

<强> *溶液* 我想到了。我已经附上了以下解决方案:

而不是使用RxNode,我选择使用Rx.Observable.fromEvent()。

节点流发出事件,无论是新数据,错误还是完整事件。

所以 fromEvent 静态运算符正在侦听&#39;数据&#39; event并为每个事件创建一个新的Observable。

然后我合并所有这些,并订阅。这是代码:

let parentStream = Rx.Observable.from(data_array);
parentStream.map((url)=> { return createEventStream(url); } ).mergeAll().subscribe(x => console.log(x), (e)=> console.log('Error', e), console.log('Complete'));

function createEventStream(url){
  return Rx.Observable.fromEvent(x(url, '#centercol ul li', [{name: 'a', link: 'a@href'}]).write().pipe(JSONStream.parse('*')), 'data');
}