我有一个Angular 2服务:
import {Storage} from './storage';
import {Injectable} from 'angular2/core';
import {Subject} from 'rxjs/Subject';
@Injectable()
export class SessionStorage extends Storage {
private _isLoggedInSource = new Subject<boolean>();
isLoggedIn = this._isLoggedInSource.asObservable();
constructor() {
super('session');
}
setIsLoggedIn(value: boolean) {
this.setItem('_isLoggedIn', value, () => {
this._isLoggedInSource.next(value);
});
}
}
一切都很好。但是我有另一个不需要订阅的组件,它只需要在某个时间点获得isLoggedIn的当前值。我该怎么做呢?
一个类似的答案被否决了。但我认为我可以证明我在这里提出的建议适用于有限的情况。
虽然一个可观察对象确实没有当前值,但通常它会有一个立即可用的值。例如,对于redux / flux / akita存储,您可以根据一些可观察的数据从中央存储请求数据,这些值通常会立即可用。
如果是这种情况,那么当您订阅时,该值将立即返回。
假设你有一个对服务的调用,在完成时你想从你的商店中获得一些东西的最新值,这可能不会发出:
你可以尝试这样做(你应该尽可能地把事情“放在管道里”):
serviceCallResponse$.pipe(withLatestFrom(store$.select(x => x.customer)))
.subscribe(([ serviceCallResponse, customer] => {
// we have serviceCallResponse and customer
});
这样做的问题是它会阻塞,直到第二个可观察对象发出一个值,而这可能永远不会发生。
我发现自己最近只需要在一个值立即可用的情况下评估一个可观察到的值,更重要的是,我需要能够检测到它是否可用。我最后是这样做的:
serviceCallResponse$.pipe()
.subscribe(serviceCallResponse => {
// immediately try to subscribe to get the 'available' value
// note: immediately unsubscribe afterward to 'cancel' if needed
let customer = undefined;
// whatever the secondary observable is
const secondary$ = store$.select(x => x.customer);
// subscribe to it, and assign to closure scope
sub = secondary$.pipe(take(1)).subscribe(_customer => customer = _customer);
sub.unsubscribe();
// if there's a delay or customer isn't available the value won't have been set before we get here
if (customer === undefined)
{
// handle, or ignore as needed
return throwError('Customer was not immediately available');
}
});
请注意,对于以上所有内容,我都使用subscribe来获取值(正如@Ben讨论的那样)。没有使用.value属性,即使我有一个行为主体。
唯一的方法,你应该得到值“出”一个可观察对象/主题是与订阅!
如果你在使用getValue()你在做一些声明式的命令。它是一个逃生口,但是99.9%的情况下你不应该使用getValue()。getValue()会做一些有趣的事情:如果主题已经取消订阅,它会抛出一个错误,如果主题已经死亡,它会阻止你获得一个值,因为它是错误的,等等。但是,再一次地,它是在罕见情况下的一个逃生口。
有几种方法可以以“Rx-y”方式从Subject或Observable中获取最新的值:
Using BehaviorSubject: But actually subscribing to it. When you first subscribe to BehaviorSubject it will synchronously send the previous value it received or was initialized with.
Using a ReplaySubject(N): This will cache N values and replay them to new subscribers.
A.withLatestFrom(B): Use this operator to get the most recent value from observable B when observable A emits. Will give you both values in an array [a, b].
A.combineLatest(B): Use this operator to get the most recent values from A and B every time either A or B emits. Will give you both values in an array.
shareReplay(): Makes an Observable multicast through a ReplaySubject, but allows you to retry the observable on error. (Basically it gives you that promise-y caching behavior).
publishReplay(), publishBehavior(initialValue), multicast(subject: BehaviorSubject | ReplaySubject), etc: Other operators that leverage BehaviorSubject and ReplaySubject. Different flavors of the same thing, they basically multicast the source observable by funneling all notifications through a subject. You need to call connect() to subscribe to the source with the subject.
可以创建订阅,然后在获取第一个发出的项之后销毁订阅。在下面的例子中,pipe()是一个函数,它使用一个可观察对象作为输入,并返回另一个可观察对象作为输出,同时不修改第一个可观察对象。
用Angular 8.1.0包"rxjs": "6.5.3", "rxjs-observable": "0.0.7"创建的示例
ngOnInit() {
...
// If loading with previously saved value
if (this.controlValue) {
// Take says once you have 1, then close the subscription
this.selectList.pipe(take(1)).subscribe(x => {
let opt = x.find(y => y.value === this.controlValue);
this.updateValue(opt);
});
}
}
一个类似的答案被否决了。但我认为我可以证明我在这里提出的建议适用于有限的情况。
虽然一个可观察对象确实没有当前值,但通常它会有一个立即可用的值。例如,对于redux / flux / akita存储,您可以根据一些可观察的数据从中央存储请求数据,这些值通常会立即可用。
如果是这种情况,那么当您订阅时,该值将立即返回。
假设你有一个对服务的调用,在完成时你想从你的商店中获得一些东西的最新值,这可能不会发出:
你可以尝试这样做(你应该尽可能地把事情“放在管道里”):
serviceCallResponse$.pipe(withLatestFrom(store$.select(x => x.customer)))
.subscribe(([ serviceCallResponse, customer] => {
// we have serviceCallResponse and customer
});
这样做的问题是它会阻塞,直到第二个可观察对象发出一个值,而这可能永远不会发生。
我发现自己最近只需要在一个值立即可用的情况下评估一个可观察到的值,更重要的是,我需要能够检测到它是否可用。我最后是这样做的:
serviceCallResponse$.pipe()
.subscribe(serviceCallResponse => {
// immediately try to subscribe to get the 'available' value
// note: immediately unsubscribe afterward to 'cancel' if needed
let customer = undefined;
// whatever the secondary observable is
const secondary$ = store$.select(x => x.customer);
// subscribe to it, and assign to closure scope
sub = secondary$.pipe(take(1)).subscribe(_customer => customer = _customer);
sub.unsubscribe();
// if there's a delay or customer isn't available the value won't have been set before we get here
if (customer === undefined)
{
// handle, or ignore as needed
return throwError('Customer was not immediately available');
}
});
请注意,对于以上所有内容,我都使用subscribe来获取值(正如@Ben讨论的那样)。没有使用.value属性,即使我有一个行为主体。