rxjs在处理数据之前检查流是否为空

时间:2016-09-26 08:45:04

标签: javascript rxjs

我们有以下流。

const recorders = imongo.listCollections('recorders')
    .flatMapConcat(names => {
        const recorders = names
            .map(entry => entry.name)
            .filter(entry => !_.contains(
                ['recorders.starts',
                 'recorders.sources',
                 'system.indexes',
                 'system.users'],
                entry));
        console.log(recorders);
        return Rx.Observable.fromArray(recorders);
    });

recorders.isEmpty()
    .subscribe(
        empty => {
            if(empty) {
                logger.warn('No recorders found.');
            }
        },
        () => {}
    );

recorders.flatMapConcat(createRecorderIntervals)
    .finally(() => process.exit(0))
    .subscribe(
        () => {},
        e => logger.error('Error while updating: %s', e, {}),
        () => logger.info('Finished syncing all recorders')
    );

如果流是空的,那么我们不想createRecorderIntervals。上面的代码正在运行。但是,检查流是否为空,导致console.log执行两次。为什么会这样?我能以某种方式解决它吗?

编辑:所以,经过重新思考后,我采取了以下方式,感谢@ Martin的回答

const recorders = imongo.listCollections('recorders')
    .flatMapConcat(names => {
        const recorders = names
            .map(entry => entry.name)
            .filter(entry => !_.contains(
                ['recorders.starts',
                 'recorders.sources',
                 'system.indexes',
                 'system.users'],
                entry));

        if(!recorders.length) {
            logger.warn('No recorders found.');
            return Rx.Observable.empty();
        }

        return Rx.Observable.fromArray(recorders);
    })
    .flatMapConcat(createRecorderIntervals)
    .finally(() => scheduleNextRun())
    .subscribe(
        () => {},
        e => logger.error('Error while updating: %s', e, {}),
        () => logger.info('Finished syncing all recorders')
    );

1 个答案:

答案 0 :(得分:1)

当您在subscribe()上调用Observable方法时,会导致创建整个运算符链,并在您的情况下调用imongo.listCollections('recorders')两次。

您可以在调用flatMapConcat(createRecorderIntervals)之前插入运算符,以检查结果是否为空。我特别想到其中一个,但可能还有其他更适合您的需求:

  • takeWhile() - 将谓词作为参数,并在返回onComplete时发出false

然后您的代码将如下所示:

const recorders = imongo.listCollections('recorders')
    .flatMapConcat(names => {
        ...
        return Rx.Observable.fromArray(recorders);
    })
    .takeWhile(function(result) {
        // condition
    })
    .flatMapConcat(createRecorderIntervals)
        .finally(() => process.exit(0))
        .subscribe(...);

我不知道你的代码到底是做什么的,但我希望你明白这个想法。

编辑:如果您希望在整个Observable为空时收到通知,而不是多种方式:

  • do()运算符和自定义Observer对象。您将编写一个自定义观察者,并在do()之前使用.flatMapConcat(createRecorderIntervals)运算符进行设置。此对象将计算其next回调被调用的次数,以及前一个Observable何时完成,您可以判断是否至少有一个或根本没有结果。

  • 创建ConnectableObservable。这个可能与我们一开始就做的最相似。您可以使用recorders运算符将ConnectableObservable变为publish()。然后,您可以订阅多个观察者,而无需触发操作员链。如果您订阅了所有Observers,请致电connect(),它将按顺序向所有观察者发出值:

    var published = recorders.publish();
    
    published.subscribe(createObserver('SourceA'));
    published.subscribe(createObserver('SourceB'));
    
    // Connect the source
    var connection = published.connect();
    

    在您的情况下,您将创建两个Subjects(因为它们同时充当Observable和Observer)并将其中一个链接到isEmpty(),将第二个链接到flatMapConcat() }。有关详细信息,请参阅文档:http://reactivex.io/documentation/operators/connect.html

我认为第一个选项对你来说实际上更容易。