繁体   English   中英

RxJS订阅有两个参数

[英]RxJS Subscribe with two arguments

我有两个要合并的可观察对象,并且在订阅中使用两个参数或仅使用一个。 我尝试了.ForkJoin,.merge,.concat,但无法实现我想要的行为。

例:

obs1: Observable<int>;
obs2: Observable<Boolean>;

save(): Observable<any> {
   return obs1.concat(obs2);
}

然后在使用此功能时:

service.save().subscribe((first, second) => {
    console.log(first); // int e.g. 1000
    console.log(second); // Boolean, e.g. true
});

要么

service.save().subscribe((first) => {
    console.log(first); // int e.g. 1000
});

是否有可能完全得到这种行为?

希望有人能帮忙!

编辑:

在我的特定用例中, obs1<int>obs2<bool>是两个不同的发布请求: obs1<int>是实际的保存功能,而obs2<bool>检查是否正在运行其他服务。

一旦请求完成,需要obs1<int>的值来重新加载页面,如果服务正在运行,则需要obs2<bool>的值以显示消息-独立于obs1<int>

因此,如果obs2<bool>obs1<int>之前发出,那不是问题,该消息在重新加载之前得到显示。 但是,如果obs1<int>obs2<bool>之前发出,则页面将被重新加载,并且消息可能不再显示。

我之所以这样说是因为,在给出答案的情况下,值是在其他可观察对象的onComplete之前还是之后发出的,都会有不同的行为,这可能会影响用例。

您可以为此使用forkJoin 称它们为并行,然后如果它们中的任何一个存在,则执行某些操作。

let numberSource = Rx.Observable.of(100);
let booleanSource = Rx.Observable.of(true);

Rx.Observable.forkJoin(
  numberSource,
  booleanSource
).subscribe( ([numberResp, booleanResp]) => {
  if (numberResp) {
    console.log(numberResp);
    // do something
  } else if (booleanResp) {
    console.log(booleanResp);
    // do something
  }
});

有几个操作员可以完成此操作:

合并最新

该运算符将结合两个可观察对象发出的最新值,如大理石图所示:

Combine最新的大理石图

obs1: Observable<int>;
obs2: Observable<Boolean>;

save(): Observable<any> {
   return combineLatest(obs1, obs2);
}

save().subscribe((val1, val2) => { 
   // logic
});

压缩

Zip运算符将等待两个可观察对象发出值,然后再发出一个值。

拉链大理石图

obs1: Observable<int>;
obs2: Observable<Boolean>;

save(): Observable<any> {
   return zip(obs1, obs2);
}

save().subscribe((vals) => { 
   // Note Vals = [val1, val2]
   // Logic
});

或者如果您想对数组使用解构

save().subscribe(([val1, val2]) => {
   // Logic
});

WithLatestFrom

WithLatestFrom发出可观察WithLatestFrom发出的最后一个值的组合,请注意,此运算符从另一个可观察对象中跳过没有对应值的所有值。

从大理石图到最新

save: obs1.pipe(withLatestFrom(secondSource))

save().subscribe(([val1, val2]) => {
    // Logic
});

您可以使用zip静态方法代替concat运算符。

save(): Observable<any> {
   return zip(obs1, obs2);
}

然后,您应该可以执行以下操作:

service.save().subscribe((x) => {
    console.log(x[0]); // int e.g. 1000
    console.log(x[1]); // Boolean, e.g. true
});

使用的确切运算符取决于您要解决的特定细节。

一个有效的选择是使用combineLatest - Docs

obs1$: Observable<int>;
obs2$: Observable<Boolean>;
combined$ = combineLatest(obs1$, obs2$);

combined$.subscribe(([obs1, obs2]) => {
  console.log(obs1);
  console.log(obs2);
})

Concat通过流发出两个事件,一个事件在另一个事件完成之后,这不是您要的。

合并将以相同的方式发出两个事件,但顺序是它们实际上最终完成,而不是您要执行的操作。

您想要的是同一流事件中两个项目的值。 forkJoin和zip和CombineLatest会执行此操作,但您会因此而陷入困境,因为它们都发出了无法在subscribe中正确访问的值的数组。

每当压缩在一起的所有项目都按顺序发出时,zip就会发出,因此,如果可观察到的1发出1,2,3,并且可观察到的两个发出4,5; zip的排放量将为[1,4],[2,5]。

CombineLatest每次都会发射一次,所以您会得到类似[1,4],[2,4],[2,5],[3,5]之类的东西(取决于确切的发射顺序)。

最终forkJoin只发出一次,它里面的每个项目实际上都完成了一次,然后完成了。 这可能是您最想要的,因为您似乎正在“节省”。 如果这些示例流中的任何一个均未完成,则forkJoin将永远不会发出,但是如果它们都在其最终值之后完成,则forkjoin将仅给出一个发出:[2,5]。 我喜欢这样做,因为它是“最安全”的操作,因为它可以确保所有流都正确完成,并且不会造成内存泄漏。 通常,在“节省”时,您只期望一次发射,因此也更加明确。 每当您看到forkForin时,您就知道您正在处理单个排放流。

我个人会这样:

obs1: Observable<int>;
obs2: Observable<Boolean>;

save(): Observable<any> {
   return forkJoin(obs1, obs2);
}

service.save().subscribe(([first, second]) => {
    console.log(first); // int e.g. 1000
    console.log(second); // Boolean, e.g. true
});

Typescript提供了这样的语法来访问长度已知的数组中的项目,但是无法在预订成功函数中真正创建多个参数,因为它的接口仅接受单个参数。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM