簡體   English   中英

RxJS:組合兩個 observable,因此 observable 僅在第一個 observable 的值為 true 時才發出

[英]RxJS: Combine two observables so the observable only emits if the value of the first observable is true

我目前正在嘗試使用 observables 實現一個簡單的離線/在線同步機制。

基本上,我有兩個可觀察的:

  1. Connection observable:第一個 observable 為我提供了是否有 Internet 連接的信息。 當網絡狀態改變時發出
  2. Data observable:第二個 observable 有需要同步的數據。 當有新數據要同步時發出

我想要實現的是結合上述可觀察的,以便:

  • 只要連接狀態為false ,組合的 observable 就不應發射。 在這種情況下,可觀察數據應保留其狀態
  • 只要連接狀態為true ,組合的 observable 應該在每次數據 observable 中有數據時發出
  • 如果連接狀態從false切換到true ,它應該為可觀察數據上的每個值發出

當前使用 filter 和 combineLatest 的小例子可以在這里找到:https ://codesandbox.io/s/offline-sync-s5lv49?file=/src/index.js

不幸的是,這根本不符合預期。

是否有任何操作員來實現所需的行為? 作為替代方案,我當然可以輪詢連接狀態並每隔 X 秒發出一次。 但理想情況下,我想要一個干凈的 Observable 組合,盡管我對什么運算符最有意義有點迷茫。

為了澄清這個想法:我需要同步所有數據,而不僅僅是最新的。 所以可觀察的數據應該緩沖數據。

看起來是在正確的道路上,可以做以下事情:

combineLatest([
  offlineOnlineSubject,
  dataSubject
])
  .pipe(
    filter(([online, counter]) => online),
  )
  .subscribe(([online, counter]) => {
    syncedIndicator.textContent = counter;
  });

因此,當我們處於offline模式時,我將所有發出的數據存儲在緩沖區中,一旦我們從離offline更改為online ,我只需發出緩沖區中的所有內容:

let dataBuffer = [];
let isPreviouslyOnline = false;

combineLatest([dataSubject, offlineOnlineSubject])
  .pipe(
    filter(([data, isOnline]) => {
      if (!isOnline) {
        if (!isPreviouslyOnline) {
          dataBuffer.push(data);
        }

        isPreviouslyOnline = false;
        return false;
      }

      return true;
    }),
    switchMap(([data]) => {
      isPreviouslyOnline = true;
      if (dataBuffer.length > 0) {
        const tempData = [...dataBuffer];
        dataBuffer = [];

        return from(tempData);
      } else {
        return of(data);
      }
    })
  )
  .subscribe((data) => {
    console.log("Data is: ", data);
  });

代碼沙箱: https ://codesandbox.io/s/offline-sync-forked-k38kc3?file=/src/index.js

我認為它有效,但感覺不太好,試圖使用本機rxjs緩沖區運算符來實現它,但無法弄清楚如何。 很想看看是否有人有更好/更清潔的解決方案。

在搜索了術語“門”之后,我發現了以下堆棧溢出問題並發布: 條件發射延遲與 rxjs

基本上,答案是使用 delayWhen 來達到預期的結果。

我在這里更新了一個例子: https ://codesandbox.io/s/offline-sync-experiments-nimoox?file=/src/index.js:0-1357

關鍵部分是:

const offlineOnlineSubject = new BehaviorSubject(false);
const dataSubject = new Subject();

const triggerFn = (_) => offlineOnlineSubject.pipe(filter((v) => v));

dataSubject.pipe(delayWhen(triggerFn)).subscribe((counter) => {
  console.log("Syncing data", {
    counter
  });

  syncedIndicator.innerHTML += `<li>${counter}</li>`;
});

包裝在自定義打字稿運算符中:

import { MonoTypeOperatorFunction, Observable } from 'rxjs';
import { delayWhen, filter } from 'rxjs/operators';

export function gate<T>(gateTrigger: Observable<boolean>): MonoTypeOperatorFunction<T> {
  const gateTriggerFn = () => gateTrigger.pipe(
    filter((v) => v)
  );

  return (source: Observable<T | null | undefined>) => source.pipe(
    delayWhen(gateTriggerFn)
  );
}

到目前為止,這個解決方案似乎正在做我打算做的事情。

暫無
暫無

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

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