const value = await this.observableMethod().toPromise();
你需要使用行为主体,
它将为您提供可观察对象发布的最新值。
BehaviorSubject提供一个名为value
的getter
属性来获取通过它传递的最新值。
StackBlitz
//Declare a Subject, you'll need to provide a default value.
const subject: BehaviorSubject<string> = new BehaviorSubject("a");
用法:
console.log(subject.value); // will print the current value
如果你想隐藏你的行为主体,只暴露它的价值,比如说从服务中,你可以使用这样的getter。
export class YourService {
private subject = new BehaviorSubject('random');
public get subjectValue() {
return this.subject.value;
}
}
快速回答:
…我只需要当前值一次,而不是新值,因为它们即将出现。。。
您仍将使用subscribe
,但使用pipe(take(1))
时,它会给您一个值。
例如,myObs$.pipe(take(1)).subscribe(value)=
另请参见:比较
first()
、take(1)
或single()
详细回答:
(或异步管道(如果使用角度)
BehaviorSubject
肯定有它的位置,当我开始使用RxJS时,我经常使用bs.value()
来获取值。随着RxJS流在整个应用程序中传播(这正是您想要的!),这样做将变得越来越困难。通常,您会看到.asObservable()
用于“隐藏”底层类型,以防止有人使用.value()
——起初这似乎很重要,但您会开始理解为什么会随着时间的推移而这样做。此外,你迟早会需要一个不是行为主体的值,而且没有办法做到这一点。
不过,回到最初的问题。尤其是如果你不想通过使用
行为主体
来作弊。
更好的方法是始终使用
subscribe
获取值。
obs$.pipe(取(1)).subscribe(值)=
或者
obs$。管道(first())。订阅(value=
如果流已完成,则这两个值之间的差异为
first()
将出错;如果流已完成或没有立即可用的值,则take(1)
将不会发出任何可见值。
注意:这被认为是更好的练习,即使你使用的是行为主体。
但是,如果您尝试上面的代码,observable的“值”将被“卡住”在subscribe函数的闭包中,并且您可能在当前范围内需要它。如果你真的必须这样做的话,解决这个问题的一个方法是:
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);
重要的是要注意,上面的subscribe调用并不等待值。如果现在没有可用的功能,那么subscribe函数将永远不会被调用,我特意将unsubscribe调用放在那里,以防止它“稍后出现”。
因此,这不仅看起来非常笨拙——它不适用于不立即可用的东西,比如http调用的结果值,而且它实际上适用于行为主题(或者更重要的是,它是一个上游的行为主体*,或者一个接受两个
行为主体
值的CombineRelateTest
)并且绝对不要去做(obs$作为行为主体)
-啊!
前面的例子总体上仍然被认为是一个糟糕的做法——一团糟。如果我想查看一个值是否立即可用,并且能够检测它是否可用,我只执行以前的代码样式。
如果您能够尽可能长时间地保持所有内容都是可观察的,并且只在您绝对需要值时订阅,而不是尝试将值“提取”到包含范围中,那么您的情况会好得多,这就是我在上面所做的。
eg.比方说,如果你的动物园开放,我们想报告我们的动物。你可能认为你想要的'提取'值的
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!');
}
}
如果zooOpen$
来自Web服务,该怎么办?前面的示例将如何工作?实际上,服务器的速度有多快并不重要——如果zooOpen$
是一个可观察的http,那么上面的代码就永远不会有值
如果您想在该函数的“外部”使用此报告,该怎么办。您现在已将警报
锁定到此方法中。如果您必须在其他地方使用该报告,则必须复制该报告
与其试图访问函数中的值,不如考虑创建一个新的可观察的函数,甚至不订阅它。
取而代之的是,它返回一个可以在“外部”使用的新的可观察对象。
通过将一切都保持为可观察的,并使用
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!');
}
});
}
上面创建了一个新的可观察对象,因此我们可以在其他地方运行它,如果我们愿意的话,可以使用更多的管道。
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()));
注意以下内容:
在我绝对需要之前我不会订阅-在这种情况下,这超出了功能范围
- “驱动”可观察对象是
zooOpen$
,它使用switchMap
来“切换”到不同的可观察对象,该可观察对象最终是从getZooReport()
返回的 - 如果
zooOpen$
发生任何变化,则其工作方式将取消所有操作,并在第一个开关映射内重新启动。阅读有关开关地图的更多信息。
- 注意:
switchMap
中的代码必须返回一个新的可观察值。您可以使用('hello')的快速创建一个对象,或者返回另一个可观察对象,例如combinelateest
- 同样:
map
必须只返回一个常规字符串
当我开始在脑海中记下必须订阅才能订阅时,我突然开始编写更高效、更灵活、更干净和可维护的代码。
另一个最后注意事项:如果您使用Angular的这种方法,您可以通过使用
|async
管道获得上面的zoo报告,而无需单个订阅
。这是一个很好的例子,说明了在实践中“必须先订阅才能订阅”的原则。
// in your angular .ts file for a component
const zooReport$ = this.getZooReport();
在模板中:
<pre> {{ zooReport$ | async }} </pre>
请参见我的回答:
https://stackoverflow.com/a/54209999/16940
为避免混淆,上文未提及:
tap()。如果您不熟悉该操作员,请仔细阅读。RxJS使用“管道”和tap()
操作符是一种“轻敲管道”的方法,可以查看管道中有什么
请参阅中的“将toPromise()与async/await一起使用,以将最后一个可观察值作为promise发出”https://benlesh.medium.com/rxjs-observable-interop-with-promises-and-async-await-bebb05306875
问题内容: 我需要一个Java程序来获取 没有时间戳 的 当前日期 : 给我日期和时间戳。 但是我只需要日期,没有时间戳。我使用此日期与另一个没有时间戳的日期对象进行比较。 在印刷时 d应打印。 问题答案: 一个对象 是 一种时间戳的-它包含自00:00:00 1970年1月1日,UTC毫秒数。因此,您不能使用标准对象仅包含一天/一个月/一年而没有时间。 据我所知,在标准Java API中,没有真
问题内容: 我想在应用程序中连接到wifi网络。 码: 但是问题是我不知道。如何获取WiFi网络的SSID ? 问题答案: 如果您想获得所有可用的wifi: 如果要连接wifi ssid: 如果您想添加新的wifi设置,我已在下面编写了演示应用程序:
问题内容: 我想检查一个版本已更改/获取具有Dropbox上共享链接的文本文件的元数据。我不会使用dropbox api,因为它会使用户使用自己的帐户。我希望他们链接到我的帐户,但是我不能手动执行此操作,因为以后可能会更改密码。 所以:没有身份验证令牌,只需从Dropbox的共享链接获取元数据,以便我可以检查版本更改以及版本是否已更改,请下载新文件的内容。 也:我也乐意接受其他建议以使这项工作也可
我需要找到一种方法,在不将图片保存到图库的情况下,将图片从相机捕获到位图中。我看到的所有使用“MediaStore.ACTION\u IMAGE\u CAPTURE”的方法都是在传递位图之前将捕获的图片保存到库中。
问题内容: 我有一个Angular 2服务: 一切正常。但是我还有另一个不需要订阅的组件,它只需要在某个时间点获取isLoggedIn的当前值即可。我怎样才能做到这一点? 问题答案: 一个或没有的电流值。发出值时,将其传递给订户并使用它完成。 如果要使用当前值,请使用专门用于该目的的值。保留最后发出的值,并立即将其发送给新订户。 它还具有一种获取当前值的方法。
问题内容: 例如,使用winamp(至少在Windows上),您可以在后台以winamp播放全屏游戏,并使用媒体按钮*控制声音。Winamp不需要聚焦,可以使游戏继续全屏显示。 我更喜欢用Java编写此代码,但这可能行不通(在Java afaik中很难捕获没有重点的击键),因此任何C#解决方案也都可以。 因此,基本问题是:如何在没有重点的情况下捕获击键? *)我相信“后退/前进/停止/邮件/搜索/