angular - IF/ELSE IF/ELSE 以 Observable 作为条件
问题描述
我正在尝试创建一种方法来返回可以存储在三个位置之一的设置。我创建了三个可观察对象,每个对象都尝试从源中检索设置值。我希望能够以这样的方式“加入”这些以创建一个 IF/ELSE IF/ELSE 构造,以便最终只有一个 Observables 发出设置值。从一个 observable 移到下一个 observable 的条件是前一个“失败”,即发出一个未通过条件的值。尝试每个选项的顺序很重要。
所以到目前为止我的方法看起来像这样:
getSetting(settingName: string): Observable<any> {
const optionOne$ = this.getItemAtFirst(settingName).pipe(
take(1),
filter(setting => setting && this.isSettingValid(settingName, setting)));
const optionTwo$ = this.getItemAtSecond().pipe(
take(1),
filter(setting => setting && this.isSettingValid(settingName, setting)));
const optionThree$ = of(this.defaultSettingValue);
return merge(optionOne$, optionTwo$, optionThree$);
}
这显然不起作用,因为merge
没有提供我需要的选择效果。
有什么建议么?提前致谢!
解决方案
编辑:TL;DR
替换为merge
并concat
添加first
到您的管道concat
:
concat(optionOne$, optionTwo$, optionThree$)
.pipe(
first()
);
concat
按顺序订阅每个 observable,意思optionOne$
是首先订阅,它发出它的值,当它完成时,它被取消订阅,然后concat
订阅optionTwo$
,等等......直到所有的 observables 完成,然后最后发出所有的值作为大批。添加first
只是缩短了这个过程,因为它在发出第一个值之后完成了连接。
您确实需要检查concat
will 中的所有 observables 是否完成,否则您可能会遇到其中一个永远不会发出或完成的条件,这意味着您永远不会获得从concat
.
——
假设您isSettingValid()
在验证失败时返回 false,那么只需将pipe()
with添加first()
到concat()
. 请参阅下面稍作修改的版本,以及此处的stackblitz。
这篇文章也很翔实。我推荐这篇文章,它有很酷的 gif 来解释操作符以及它们是如何工作的——当我试图找出类似的东西时,我总是会回到它。
我认为这回答了您的问题,因为它发出第一个通过验证的值并忽略其余的值。
import { of, Observable, concat } from 'rxjs';
import { take, filter, first } from 'rxjs/operators';
function isSettingValid(setting): boolean {
return setting !== 'error' ? true : false;
}
function getSetting(): Observable<any> {
const optionOne$ = of('error')
.pipe(
take(1),
filter(setting => isSettingValid(setting))
);
const optionTwo$ = of('second')
.pipe(
take(1),
filter(setting => isSettingValid(setting))
);
const optionThree$ = of('default').pipe(
take(1),
filter(setting => isSettingValid(setting))
);
return concat(optionOne$, optionTwo$, optionThree$)
.pipe(
first() // emits only the first value which passes validation then completes
);
}
getSetting()
.subscribe((setting) => {
console.log(setting);
})
我还建议删除setting &&
, 就像在我的代码段中一样,并将空检查放在您的验证函数中 - 如果您这样做,它只会使过滤器更容易阅读 imo。为了使其更简洁,您可以考虑将take(1)
andfilter()
替换为first
and 一个具有相同结果的谓词函数:
const optionOne$ = of('error')
.pipe(
first(setting => isSettingValid(setting))
);
推荐阅读
- python - Django - 创建超级用户
- scala - 通过创建 JSON 对象使用数据生成器的空手道 DSL 返回 null
- javascript - 创建表单输入的实时预览
- android-webview - 有没有办法缩放视频元素的分辨率以匹配来自媒体流的分辨率?
- java - Spring boot rabbitmq 配置繁重操作
- c++ - C++ 继承:具有基类类型的变量
- assembly - 更改为保护模式会导致三重故障
- python-3.x - __init__ 需要什么
- python - 如何使用 pandas 创建具有有限数量新列的数据透视表?
- python - Flask 视图接受 1 个位置参数,但给出了 2 个