Eri*_*icC 34 observable rxjs angular
标题说明了一切.如何在不订阅的情况下从Observable获取当前值?我只想要当前值一次而不是新值,因为它们正在进入......
Ank*_*ngh 33
你需要使用BehaviorSubject,
- BehaviorSubject类似于ReplaySubject,只是它只记住最后一个发布.
- BehaviorSubject还要求您为其提供默认值T.这意味着所有订阅者将立即收到一个值(除非它已经完成).
它将为您提供Observable发布的最新值.
BehaviorSubject提供了一个getter名为的属性,value用于获取通过它传递的最新值.
//Declare a Subject, you'll need to provide a default value.
var subject: BehaviorSubject<string> = new BehaviorSubject("a");
Run Code Online (Sandbox Code Playgroud)
用法:
console.log(subject.value); // will print the current value
Run Code Online (Sandbox Code Playgroud)
快速回答:
...我只希望当前值一次而不是新值,因为它们即将出现...
您仍将使用subscribe,但是pipe(take(1))这样可以给您一个单一的价值。
例如。 myObs$.pipe(take(1)).subscribe(value => alert(value));
另请参见:比较first(),take(1)或single()
更长的答案:
subscribe()(或异步管道(如果使用Angular))
BehaviorSubject肯定有它的位置,当我开始使用RxJS时,我经常会做bs.value()以获取价值。随着您的RxJS流在整个应用程序中传播(这就是您想要的!),这样做将变得越来越困难。通常,您实际上经常会看到.asObservable()习惯于“隐藏”底层类型以防止某人使用.value()-乍一看,这似乎很卑鄙,但您将逐渐理解为什么它会随着时间的推移完成。此外,你迟早会需要的东西值不是一个BehaviorSubject,所以才没有成为一个办法让它如此。
回到最初的问题。特别是如果您不想使用来“作弊” BehaviorSubject。
更好的方法是始终使用subscribe以获取价值。
obs$.pipe(take(1)).subscribe(value => { ....... })
要么
obs$.pipe(first()).subscribe(value => { ....... })
如果流已经完成,则两者之间的差异first()将出错,并且take(1)如果流已完成或没有立即可用的值,则两者之间不会发出任何可观察到的东西。
注意:即使您正在使用BehaviorSubject,这也被认为是更好的做法。
但是,如果尝试上述代码,则可观察对象的“值”将“卡在”订阅函数的闭包内,并且您很可能在当前作用域中需要它。解决这个问题的一种方法是:
const obsValue = undefined;
const sub = obs$.pipe(take(1)).subscribe(value => obsValue = value);
sub.unsubscribe();
// we will only have a value here if it was IMMEDIATELY available
alert(obsValue);
Run Code Online (Sandbox Code Playgroud)
重要的是要注意,上面的订阅调用不会等待值。如果没有立即可用的订阅函数,则永远不会调用该函数,而我故意将取消订阅的调用放在那儿,以防止其“稍后出现”。
因此,这不仅显得笨拙-不适用于无法立即使用的内容(例如来自http调用的结果值),而且实际上可以与行为主题一起使用(或更重要的是*上游,并且已知为BehaviorSubject **或combineLatest采用两个BehaviorSubject值的)。绝对不要去(obs$ as BehaviorSubject)-恩!
前面的示例通常仍然被认为是一种不好的做法-这是一团糟。仅当我想查看某个值是否立即可用并能够检测出它是否可用时,才执行以前的代码样式。
如果您可以将所有内容保持在尽可能长的可观察范围内,并且只有在您绝对需要该值时才订阅,而不是尝试将一个值“提取”到一个包含范围(我正在这样做),您的状况就会好得多。以上。
例如。假设您的动物园开放,我们想报告我们的动物。您可能会认为您想要这样的“提取”值zooOpen$:
zooOpen$: Observable<boolean> = of(true); // is the zoo open today?
bear$: Observable<string> = of('Beary');
lion$: Observable<string> = of('Liony');
runZooReport() {
// we want to know if zoo is open!
// this uses the approach described above
const zooOpen: boolean = undefined;
const sub = this.zooOpen$.subscribe(open => zooOpen = open);
sub.unsubscribe();
// 'zooOpen' is just a regular boolean now
if (zooOpen)
{
// now take the animals, combine them and subscribe to it
combineLatest(this.bear$, this.lion$).subscribe(([bear, lion]) => {
alert('Welcome to the zoo! Today we have a bear called ' + bear + ' and a lion called ' + lion);
});
}
else
{
alert('Sorry zoo is closed today!');
}
}
Run Code Online (Sandbox Code Playgroud)
zooOpen$来自网络服务怎么办?前面的示例将如何工作?实际上,您的服务器有多快并不重要-如果zooOpen$可以观察到http,那么您将永远不会获得上述代码的值!alert为该方法。如果您必须在其他地方使用该报告,则必须重复此操作!与其尝试访问您函数中的值,不如考虑创建新的Observable甚至不订阅它的函数!
相反,它返回可以在“外部”使用的新可观察对象。
通过将所有内容保持为可观察值并switchMap用于制定决策,您可以创建新的可观察值,而这些新观察值本身就是其他可观察值的来源。
getZooReport() {
return this.zooOpen$.pipe(switchMap(zooOpen => {
if (zooOpen) {
return combineLatest(this.bear$, this.lion$).pipe(map(([bear, lion] => {
// this is inside 'map' so return a regular string
return "Welcome to the zoo! Today we have a bear called ' + bear + ' and a lion called ' + lion;
}
);
}
else {
// this is inside 'switchMap' so *must* return an observable
return of('Sorry the zoo is closed today!');
}
});
}
Run Code Online (Sandbox Code Playgroud)
上面的代码创建了一个新的Observable,因此我们可以在其他地方运行它,并且如果需要的话,可以通过管道进行更多操作。
const zooReport$ = this.getZooReport();
zooReport$.pipe(take(1)).subscribe(report => {
alert('Todays report: ' + report);
});
// or take it and put it into a new pipe
const zooReportUpperCase$ = zooReport$.pipe(map(report => report.toUpperCase()));
Run Code Online (Sandbox Code Playgroud)
请注意以下几点:
zooOpen$,它用于switchMap“切换”到另一个可观测值,该观测值最终是从返回的getZooReport()。zooOpen$改变的话,它取消一切并在第一个内部重新开始switchMap。阅读有关switchMap的更多信息。switchMap必须返回一个新的observable。您可以使用of('hello')- 快速创建一个或返回另一个可观察到的值,例如combineLatest。map必须只返回一个常规字符串。很快,我开始刻意不要订阅,直到突然不得不开始编写更加高效,灵活,简洁和可维护的代码。
另一个最后的注意事项:如果将这种方法与Angular一起使用,则可以subscribe通过使用| async管道获得上述Zoo报告而没有一个。这是实践中“直到您必须订阅”主体的一个很好的例子。
// in your angular .ts file for a component
const zooReport$ = this.getZooReport();
Run Code Online (Sandbox Code Playgroud)
并在您的模板中:
<pre> {{ zooReport$ | async }} </pre>
Run Code Online (Sandbox Code Playgroud)
另请参阅我的回答:
上面也没有提到以避免混淆:
tap()有时可能对“从可观察到的价值中获取价值”很有用。如果您不熟悉该运算符,请仔细阅读。RxJS使用“管道”,而tap()运算符是“挖掘管道”以查看其中的一种方法。| 归档时间: |
|
| 查看次数: |
29696 次 |
| 最近记录: |