[英]How to combine two Observables into one Observable Array using RxJs
[英]RxJS: Combine two observables so the observable only emits if the value of the first observable is true
我目前正在嘗試使用 observables 實現一個簡單的離線/在線同步機制。
基本上,我有兩個可觀察的:
我想要實現的是結合上述可觀察的,以便:
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.