经过一段时间后,可观察到的运算符可以“执行”操作

时间:2018-09-27 19:33:27

标签: javascript angular typescript rxjs rxjs-pipeable-operators

在rxjs可观察的链中,经过一段设定的时间后,我该如何对可观察的当前值进行访问?本质上,我正在寻找类似tap operator的东西,但是它仅在经过一定时间而看不到可观察对象的值时才执行。因此,确实就像是轻按和超时的组合。

我在想像下面的东西

observable$.pipe(
  first(x => x > 5),
  tapAfterTime(2000, x => console.log(x)),
  map(x => x + 1)
).subscribe(...);

这是一个虚构的示例,“ tapAfterTime”功能不是真实的。但是基本的想法是,如果在订阅后经过2000毫秒并且可观察对象的值未大于5,则对可观察对象的当前值执行tapAfterTime回调函数。如果我们在2000ms之前看到一个大于5的值,则tapAfterTime回调将永远不会运行,但map函数将始终按预期运行。

是否有运营商可以实现这一目标?

3 个答案:

答案 0 :(得分:1)

也许这真的太复杂了,也许值得一看。

这个想法是要有2个不同的可观察对象,它们是通过转换源observable$来创建的,然后最终合并。

第一个Observable(我们称之为obsFilterAndMapped)是您进行过滤和映射的地方。

第二个Observable(称为obsTapDelay)是一个Observable,它在第一个Observable(即obsFilterAndMapped)发出任何时间时都会触发一个具有特定 delay 的新计时器-一旦传递了 delayTime ,则执行tapAfterTime操作-如果第一个Observable在传递 delayTime 之前发出新值,则将创建一个新计时器

这是实现此想法的代码

const stop = new Subject<any>();
const obsShared = observable$.pipe(
    finalize(() => {
        console.log('STOP');
        stop.next();
        stop.complete()
    }),
    share()
);
const delayTime = 300;
const tapAfterTime = (value) => {
    console.log('tap with delay', value)
}; 

let valueEmitted;

const obsFilterAndMapped = obsShared.pipe(
    tap(val => valueEmitted = val),
    filter(i => i > 7),
    map(val => val + ' mapped')
);

const startTimer = merge(of('START'), obsFilterAndMapped);

const obsTapDelay = startTimer.pipe(
    switchMap(val => timer(delayTime).pipe(
        tap(() => tapAfterTime(valueEmitted)),
        switchMap(() => empty()),
    )),
    takeUntil(stop),
)

merge(obsFilterAndMapped, obsTapDelay)
.subscribe(console.log, null, () => console.log('completed'))

使用这种方法,只要源tapAfterTime的发射时间长于observable$,您就可以执行delayTime动作。换句话说,这不仅适用于observable$的首次发射,而且适用于整个生命。

您可以使用以下输入来测试此类代码

const obs1 = interval(100).pipe(
    take(10),
);
const obs2 = timer(2000, 100).pipe(
    take(10),
    map(val => val + 200),
);
const observable$ = merge(obs1, obs2);

通过更多的工作,我们甚至可以考虑将valueEmitted全局变量隐藏在闭包中,但这会增加代码的复杂性,可能不值得。

答案 1 :(得分:0)

看看

还有可能是这样吗?

-

initiateTimer() {
    if (this.timerSub) {
        this.timerSub.unsubscribe();
    }

    this.timerSub = Rx.Observable.timer(2000)
        .take(1)
        .subscribe(this.showPopup.bind(this));
}

答案 2 :(得分:0)

可能是这样的:

let cancel;
observable$.pipe(
  tap((x)=>clear=setTimeout(()=>console.log(x), 2000)),
   filter(x => x > 5),
   tap(x => clearTimeout(clear)),
   map(x => x + 1)
);