簡體   English   中英

RxJS:takeUntil 忽略主題事件

[英]RxJS: takeUntil ignores Subject event

在下面的代碼示例中,目的是通過向 Subject mid$發出 1 來阻止second$的事件。

import { Subject, timer } from "rxjs";
import { switchMap, takeUntil, tap } from "rxjs/operators";

const first$ = timer(1000);
const second$ = timer(2000);

const mid$ = new Subject();

first$.pipe(
  tap(() => { 
    mid$.next(1); 
  }),
  switchMap(() => second$.pipe(
    takeUntil(mid$),
    tap(() => console.log("MISSED!"))
  )),
).subscribe();


mid$.subscribe(() => console.log("RECEIVED"));

堆棧閃電戰

但由於控制台顯示的某些原因,它不起作用:

RECEIVED
MISSED!

mid$.next(1); takeUntil(mid$)不考慮

這里的邏輯是什么?

我注意到如果我替換 line mid$.next(1); timer(0).subscribe(() => mid$.next(1)); 它按預期工作,但我想知道在 RxJS 中處理此類情況的正確方法是什么。

takeUntil 僅在下一次observable 發射時取消訂閱。 它不知道之前是否已經發出了 observable。

const first$ = timer(1000);
const second$ = timer(2000);

const mid$ = new Subject();

first$.pipe(
  tap((first) => {
    console.log('first', first)
    mid$.next(1);
    console.log('first', first)
  }),
  switchMap(() => second$.pipe(
    tap((second) => console.log('second', second)),
    takeUntil(mid$), // Unsubscribing next time mid$ emits
    tap(() => console.log("MISSED!"))
  )),
).subscribe(second => console.log('final', second));


mid$.subscribe(() => console.log("RECEIVED"));

這將記錄

// 1s passes
first 0
RECEIVED
first 0
// 1s passes
second 0
MISSED!
final 0

這是正在發生的事情:

一秒鍾過去了。 first$ 發出,然后你 switchMap 到 second$。 再過一秒,第二個$ 發出。 只是現在你告訴它在 mid$下一次發出后取消訂閱。 然而 mid$ 已經發出(並且永遠不會再次發出)。 如果您將 second$ 替換為 interval(2000) 您會明白我的意思。 “錯過了。” 將每 2 秒永久記錄一次。

它不像這樣按預期工作

const first$ = timer(1000);
const second$ = timer(2000);

const mid$ = new Subject();

first$.pipe(
  tap(() => { 
    mid$.next(1);
  }),
  switchMap(() => second$.pipe(
    takeUntil(mid$),
    tap(() => console.log("MISSED!"))
  )),
).subscribe();

因為當mid$.next(1); 到達時, switchMap的內部 observable 尚未創建。 所以, takeUntil還沒有訂閱那個mid$主題。

它適用於timer(0).subscribe(() => mid$.next(1)); (這與setTimeout(() => mid$.next(), 0)大致相同),因為在這種情況下,當mid$發出時, switchMap已經創建了內部 observable。

解決此問題的快速方法可能涉及使用BehaviorSubject而不是Subject ,因為BehaviorSubject會將最后發出的值發送給新訂閱者:

const first$ = timer(1000);
const second$ = timer(2000);

const mid$ = new BehaviorSubject(null);

first$.pipe(
  tap(() => { 
    mid$.next(1);
  }),
  switchMap(() => second$.pipe(
    // here, when `mid$` is subscribed, the subscriber will receive `1` 
    // and the entire inner observable will complete
    takeUntil(mid$),
    tap(() => console.log("MISSED!"))
  )),
).subscribe();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM