[英]RxJs: Abort a deferred and shared observable when all unsubscribe
我想創建一個運行長輪詢操作的rxjs
Observable
。 每次迭代都會發出中間結果。 當isComplete
返回 true 時, Observable
完成。
這個 function 應該表現如下
下面的代碼可以正常工作並且滿足條件(1)和(2):
function longPollingAction(fetch: () => Promise<Response>, cancel: () => {}): Observable<Response> {
return defer(() => { // defer to start running when there's a single subscriber
return from(fetch()).pipe(
expand(() => timer(1000).pipe(switchMap(fetch))),
takeWhile<Response>(isComplete, false),
);
}).pipe(share()); // share to allow multiple subscribers
}
function isComplete(r: Response): boolean {
// returns true if r is complete.
}
如何修改此代碼以滿足(3)以及? 使用當前實現,輪詢停止,但我如何調用cancel
?
您可以使用finalize
調用取消。 這可能是這樣的:
function longPollingAction(
fetch: () => Promise<Response>,
cancel: () => void
): Observable<Response> {
// defer to turn eager promise into lazy observable
return defer(fetch).pipe(
expand(() => timer(1000).pipe(switchMap(fetch))),
takeWhile<Response>(isComplete, false),
finalize(cancel),
share() // share to allow multiple subscribers
);
}
function isComplete(r: Response): boolean {
// returns true if r is complete.
}
complete
回調 tap 操作員可以訪問next
、 error
和complete
排放。 對於callback: () => void
,這就足夠了。
function longPollingAction(
fetch: () => Promise<Response>,
cancel: () => void
): Observable<Response> {
// defer to turn eager promise into lazy observable
return defer(fetch).pipe(
expand(() => timer(1000).pipe(switchMap(fetch))),
takeWhile<Response>(isComplete, false),
tap({
complete: cancel
}),
share() // share to allow multiple subscribers
);
}
function isComplete(r: Response): boolean {
// returns true if r is complete.
}
unsubscribe
回調我不認為這樣的運算符存在,但我們可以很容易地制作一個。 如果取消訂閱,此運算符只會觸發回調。 它將忽略error
,並complete
。
function onUnsubscribe<T>(
fn: () => void
): MonoTypeOperatorFunction<T> {
return s => new Observable(observer => {
const bindOn = name => observer[name].bind(observer);
const sub = s.subscribe({
next: bindOn("next"),
error: bindOn("error"),
complete: bindOn("complete")
});
return {
unsubscribe: () => {
fn();
sub.unsubscribe()
}
};
});
}
然后你可以像這樣使用它:
function longPollingAction(
fetch: () => Promise<Response>,
cancel: () => void
): Observable<Response> {
// defer to turn eager promise into lazy observable
return defer(fetch).pipe(
expand(() => timer(1000).pipe(switchMap(fetch))),
takeWhile<Response>(isComplete, false),
onUnsubscribe(cancel),
share() // share to allow multiple subscribers
);
}
function isComplete(r: Response): boolean {
// returns true if r is complete.
}
由於share
正在管理您的訂閱,並且 share 只會在refCount < 1
時取消訂閱,因此在這種情況下調用 cancel 的唯一方法是沒有訂閱者。
給貓剝皮的方法不止一種,但我會這樣做:
const onUnsubscribe = (callback: () => void) => <T>(source$: Observable<T>) =>
new Observable<T>(observer => {
let isSourceDone = false;
const subscription = source$.subscribe(
val => {
observer.next(val);
},
e => {
isSourceDone = true;
observer.error(e);
},
() => {
isSourceDone = true;
observer.complete();
}
);
return () => {
if (isSourceDone) return;
callback();
subscription.unsubscribe();
};
});
function longPollingAction(
fetch: () => Promise<Response>,
cancel: () => {}
): Observable<Response> {
const lazyFetch$ = defer(() => fetch());
return lazyFetch$.pipe(
expand(() => timer(1000).pipe(mergeMapTo(lazyFetch$))),
takeWhile<Response>(isComplete, false),
onUnsubscribe(cancel),
share()
);
}
function isComplete(r: Response): boolean {
// returns true if r is complete.
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.