问题描述
const nextClickHandler$ = merge(doA$,dob$,doC$)
,
do A$/B$/C$
是产生 HTTPRequest 或执行一些副作用的 observable,它们在一些互斥的条件下运行,其中 doA$/dob$/doC$ 处于活动状态并执行网络调用/副作用。>
用例是,在单击下一步按钮时,执行 A/B/C,如果我在单击下一步之前订阅它,我将面临如何订阅此合并 observable 的问题,即
ngOnInit(){
this.nextClickHandler$.subscribe()
}
这将急切地评估那些相互排斥的条件并执行,甚至无需单击下一步,
我尝试通过点击 goForward 订阅:
goForward(): void {
if (this.getCurrentStep() == 1) {
if (this.validateForm()) {\
//performs side-effects for either A$/B$/C$
this.nextClickHandler$.subscribe();
}
return;
}
但是现在,当我再次上 Step I 时,它不会等待下一个的点击,因为它是长期订阅,它只是急切地执行行为,这不是我想要的,我想要它们仅在单击下一步时延迟执行,我尝试了 take(1)
但这并不能解决问题,我该如何实现?
解决方法
如果您不喜欢创建多个订阅变量,
switchMap()
是一个很好的例子,但如果您想继续使用 merge()
或 mergeMap
,请尝试使用 takeUntil()
运算符。您无需每次都创建订阅变量。
你只创建一次,销毁一次,但你可以在同一个页面代码中多次使用它。
// Step-1: Create a destroy variable
destroy$: Subject<any> = new Subject();
// Step-2: Use it how many times you want
obs1$.pipe(takeUntil(this.destroy$)).subscribe();
obs2$.pipe(takeUntil(this.destroy$)).subscribe();
obs3$.pipe(takeUntil(this.destroy$)).subscribe();
.
.
.
so on...
// Step-3 : Destroy the subject
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
如果你想合并 observables,你也可以使用 combineLatest() 操作符,你可以一次订阅多个 observables。像这样:
combineLatest(obs1$,obs2$,obs3$)
.takeUntil(this.destroy$)
.subscribe(([obs1Data,obs2Data,obs3Data]) => {})
,
您可以尝试从按钮的点击事件创建一个 Observable,使用 fromEvent:
<button #sbtn>
Subscribe
</button>
@ViewChild('sbtn',{ static: true }) sbtn: ElementRef;
this.clickBtnEvent$ = fromEvent(this.sbtn.nativeElement,'click');
而不是在 init 上(或在 view init 之后)订阅那个 Observable:
this.clickBtnEvent$.pipe(
mergeMap(() => nextClickHandler$)
).subscribe( /* some logic*/);
这个 Observable 只有在你点击按钮时才会发出,实际上每次点击它。