我正在开发一个Angular应用程序,该应用程序必须以同步方式从各种来源(具有映射管道功能的BeehaviorSubjects)中获取数据。
直到现在,它都是这样完成的:
let magicNumber;
this.magicService.magicNumber$.pipe(take(1)).subscribe(val => magicNumber = val));
等这最终会成为一堆样板,因此我想做一个功能来大大减少这种样板。但是,我正在编写的函数仅用于同步动作,但是它接受任何可观察的形式。目前,我正在尝试通过将具有异步性的流传递给函数时抛出错误来强制执行此操作,并且当前实现如下所示:
export function select<T>(inStream: Observable<T>): T {
let value: T;
race(
inStream,
throwError(
new Error(
select.name +
" expects a synchronous stream. Received an asynchronous stream."
)
)
)
.pipe(take(1))
.subscribe(val => (value = val));
return value;
}
哪些服务允许我简单地写:
const magicNumber = select(this.magicService.magicNumber$);
但是,有没有更优雅的方法来执行此操作?最好是我有一些TypeScript技巧,可以让我告诉开发人员在开发过程中他们将错误类型的Pipe作为参数发送,但是我不确定是否有任何方法可以仅从类型推断中识别异步管道的同步
现在的问题是,开发人员在运行代码之前不会注意到他们做错了什么,并且由于传递异步流而使代码崩溃。
为示例起见,假设我有三个服务,userService
,basketService
,purchaseService
。
在userService
中,我有以下内容:
userData$: BehaviorSubject<UserDataStore>;
...
userName$ = userData$.pipe(
map(({ userName }) => userName));
在basketService中也是如此:
basketStore$: BehaviorSubject<BasketStore>;
...
basketContent$ = basketStore$.pipe(
map(({ content }) => content));
在purchaseService
中,我有一个http-post方法,该方法的实现如下所示:
function purchase() {
const userName = select(this.userService.userName$);
const basketContent = select(this.basketService.basketContent$);
this.http.post("http://niceUrl.com", {
userName,
basketContent
}).subscribe(
ReduceResponse
)
(此示例中简化了管道;实际上,它们确实包含重试代码和错误捕获等。)
换句话说,我正在谈论从已经存储在BehaviorSubject 中的服务中收集数据的过程,在该过程中我知道收集将是同步的,并且为此做了一个简化。
>我知道这段代码仅在流是同步的时才起作用,所以我想阻止其他程序员尝试将异步流传递到方法中。
作比较;下面的示例在实现select
方法之前的示例:
function purchase() {
let userName, basketContent;
this.userService.userName$.pipe(take(1)).subscribe(val => userName = val);
this.basketService.basketContent$.pipe(take(1)).subscribe(val => basketContent = val);
this.http.post("http://niceUrl.com", {
userName,
basketContent
}).subscribe(
ReduceResponse
)
PS!我们已经在使用组件代码中的OnPush进行严格的异步数据更新,因此无需注释在组件中异步使用RxJs