我需要像 Observable 这样的东西,它只调用一次 Web 服务,并将其结果返回给所有订阅者。订阅可能发生在通话之前或之后。我怎样才能做到这一点?
A
Subject
将为所有在之前而非之后订阅的客户提供答案。
const s: Subject<number> = new Subject();
s.next(1);
s.subscribe(x => {console.log(x)}); // will not print anything
A BehaviourSubject
需要一个虚拟初始值,在调用之前订阅的客户端将获得虚拟值而不是正确的值。
const s: BehaviorSubject<number> = new BehaviorSubject(123);
s.subscribe(x => {console.log(x)}); // will print dummy value 123, then 1
s.next(1);
我尝试创建自己的Observable
,但是在这种情况下,网络服务可能会被多次调用
let val: number|undefined = undefined;
const s = new Observable((observer) => {
if (val !== undefined) {
observer.next(val);
} else {
doMyHttpCall().subscribe({
response => {
this.val = 1;
observer.next(val);
});
}
});
s.subscribe(x => {console.log(x)});
s.subscribe(x => {console.log(x)}); // two clients may give two calls
正确的做法是什么?
import { ReplaySubject } from 'rxjs';
function createBehaviorSubjectWithoutInitialValue<T>(): ReplaySubject<T> {
return new ReplaySubject<T>(1);
}
// Usage
const behaviorSubjectWithoutInitialValue = createBehaviorSubjectWithoutInitialValue<string>();
// Subscribe to the subject
behaviorSubjectWithoutInitialValue.subscribe(value => {
console.log(value); // Output: YourValue
});
// Emit a value
behaviorSubjectWithoutInitialValue.next('YourValue');
使用共享重放
import { Observable } from 'rxjs';
import { shareReplay } from 'rxjs/operators';
function createBehaviorSubjectWithoutInitialValue<T>(source: Observable<T>): Observable<T> {
return source.pipe(shareReplay(1));
}
// Usage
const source = new Observable<string>(subscriber => {
// Emit a value
subscriber.next('YourValue');
subscriber.complete();
});
const behaviorSubjectWithoutInitialValue = createBehaviorSubjectWithoutInitialValue(source);
// Subscribe to the subject
behaviorSubjectWithoutInitialValue.subscribe(value => {
console.log(value); // Output: YourValue
});
// Later subscriptions will also get the most recent value
behaviorSubjectWithoutInitialValue.subscribe(value => {
console.log(value); // Output: YourValue
});