检查是否未完成Observable为空

时间:2017-01-11 08:29:23

标签: javascript typescript rxjs rxjs5

有没有一种好方法可以检查是否完成Observable在那个确切的时间是空的?

let cache = new ReplaySubject<number>(1);
...
// Here I want to know if 'cache' still empty or not. And, for example, fill it with initial value.
cache.isEmpty().subscribe(isEmpty => {
    if (isEmpty) {
        console.log("I want to be here!!!");
        cache.next(0);
    }
});
// but that code does not work until cache.complete()

4 个答案:

答案 0 :(得分:2)

您可以使用takeUntil()

Observable.of(true)
    .takeUntil(cache)
    .do(isEmpty => {
        if (isEmpty) {
            console.log("I want to be here!!!");
            cache.next(0);
        }
    })
    .subscribe();

然而,这只会运作一次。

另一种方式是&#34; null&#34;缓存并使用BehaviorSubject

将其初始化为空
let cache = new BehaviorSubject<number>(null as any);
...
cache
   .do(content => {
       if (content == null) {
           console.log("I want to be here!!!");
           cache.next(0);
       }
    })
    .subscribe();

当然,您可以立即使用默认值初始化缓存。

答案 1 :(得分:2)

实际上,它并不那么简单,而且接受的答案并不是非常普遍。您想在此特定时间点检查ReplaySubject是否为空。

但是,如果您想要使其真正与ReplaySubject 兼容,则还需要考虑&#34;时间的windowTime参数对于通过此对象的每个值,实时&#34; 。这意味着您的cache是否为空会及时更改

ReplaySubject方法_trimBufferThenGetEvents可以满足您的需求。不幸的是,这种方法是私密的,所以你需要做一点&#34; hack&#34;在JavaScript中并直接扩展其prototype

import { ReplaySubject } from 'rxjs';

// Tell the compiler there's a isNowEmpty() method
declare module "rxjs/ReplaySubject" {
    interface ReplaySubject<T> {
        isNowEmpty(): boolean;
    }
}

ReplaySubject.prototype['isNowEmpty'] = function() {
    let events = this._trimBufferThenGetEvents();
    return events.length > 0;
};

然后使用此ReplaySubject很简单:

let s = new ReplaySubject<number>(1, 100);
s.next(3);
console.log(s.isNowEmpty());
s.next(4);

setTimeout(() => {
    s.next(5);
    s.subscribe(val => console.log('cached:', val));
    console.log(s.isNowEmpty());
}, 200);

setTimeout(() => {
    console.log(s.isNowEmpty());
}, 400);

请注意,对isNowEmpty()的某些调用会返回true,而其他调用会返回false。例如,最后一个返回false,因为该值在此期间无效。

此示例打印:

true
cached: 5
true
false

查看现场演示:https://jsbin.com/sutaka/3/edit?js,console

答案 2 :(得分:1)

您可以使用.scan()累积您的计数,并将其映射到布尔值是否非零。 (对于种子值,它需要第二个参数,使其以0开头,因此它始终反映当前计数。)

我还添加了.filter()而不是if语句,以使其更清晰:

let cache = new ReplaySubject<number>(1);

cache
    .map((object: T) => 1)
    .scan((count: number, incoming: number) => count + incoming, 0)
    .map((sum) => sum == 0)
    .filter((isEmpty: boolean) => isEmpty)
    .subscribe((isEmpty: boolean) => {
        console.log("I want to be here!!!");
        cache.next(0);
    });

答案 3 :(得分:0)

startWith

let cache = new ReplaySubject<number>(1);

isEmpty$ = cache.pipe(mapTo(false), startWith(true));

这说:

  • 无论缓存发出什么值,都将其映射到false。 (因为发射后它不为空)
  • 如果尚未发出任何消息,则以true开始(因为这意味着它是空的)