当事情必须按顺序进行时,使用RxJS删除嵌套回调
我需要一个接一个地执行HTTP请求,但是第二个HTTP请求在第一个HTTP请求完成之前无法启动,因为第二个HTTP请求需要从第一个HTTP请求返回一个值作为参数 这里有一个嵌套回调,这很好,因为它可以工作,并且从代码中可以清楚地看到发生了什么当事情必须按顺序进行时,使用RxJS删除嵌套回调,rxjs,Rxjs,我需要一个接一个地执行HTTP请求,但是第二个HTTP请求在第一个HTTP请求完成之前无法启动,因为第二个HTTP请求需要从第一个HTTP请求返回一个值作为参数 这里有一个嵌套回调,这很好,因为它可以工作,并且从代码中可以清楚地看到发生了什么 this.isLoading = true; this.firstService.get(this.id) .subscribe((response: FirstReturnType) => { this.
this.isLoading = true;
this.firstService.get(this.id)
.subscribe((response: FirstReturnType) => {
this.firstThing = response;
this.secondService.get(this.firstThing.secondId)
.subscribe(
(response: SecondReturnType) => {
this.secondThing = response;
this.isLoading = false;
}
}
我看到人们声称嵌套回调是不好的,应该使用RxJS使其更好
然而,提出这些主张的人都无法拿出一个可行的例子。您可以吗?您可以使用
开关映射
this.firstService.get(this.id)
.烟斗(
点击((响应:FirstReturnType)=>this.firstThing=response),
switchMap((响应:FirstReturnType)=>this.secondService.get(response.secondId)),
点击((响应:SecondReturnType)=>{
第二件事=反应;
this.isLoading=false;
})
).subscribe();
重新编写代码
下面是一些与您的代码有1-1对应关系的代码,但它是扁平的
this.isLoading=true;
this.firstService.get(this.id).pipe(
mergeMap((响应:FirstReturnType)=>{
第一件事=反应;
返回this.secondService.get(response.secondId);
})
).订阅((响应:SecondReturnType)=>{
第二件事=反应;
this.isLoading=false;
});
这是正确的:您正在使用一个高阶可观测操作符将一个可观测值发出的值映射到您订阅的新可观测值。在本例中,mergeMap为您订阅并摆脱嵌套
供你考虑
想想这个。如果不使用高阶运算符,则可以清楚地查看一行中的六个服务调用(每个调用都为下一个调用提供一些值):
this.firstService.getThing(“First”).subscribe(result1=>{
this.secondService.getThing(result1.value).subscribe(result2=>{
this.thirdService.getThing(result2.value).subscribe(result3=>{
this.fourthService.getting(result3.value).subscribe(result4=>{
this.fifthService.getting(result4.value).subscribe(result5=>{
this.sixthService.getThing(result5.value).subscribe(result6=>{
日志(“结果六为:+result6.value”);
});
});
});
});
});
});
以下是与mergeMap完全相同的内容:
this.firstService.getThing(“First”).pipe(
mergeMap(result1=>this.secondService.getting(result1.value)),
mergeMap(result2=>this.thirdService.getThing(result2.value)),
mergeMap(result3=>this.fourthService.getting(result3.value)),
mergeMap(result4=>this.fifthService.getting(result4.value)),
mergeMap(result5=>this.sixthService.getThing(result5.value)),
).订阅(结果6=>{
日志(“结果六为:+result6.value”);
});
如果这还不足以说服您,那么您可以在一些函数式编程中多做一点,使其更加简洁(无需重复命名每个结果)
constpassvaluetoservice=service=>result=>service.getThing(result.value);
passValueToService(this.firstService)(“First”).pipe(
mergeMap(passValueToService(this.secondService)),
mergeMap(passValueToService(this.thirdService)),
mergeMap(passValueToService(this.fourthService)),
mergeMap(passValueToService(this.fifthService)),
mergeMap(passValueToService(this.sixth服务)),
).订阅(最终结果=>{
log(“结果六为:+finalResult.value”);
});
或者,为什么不更努力地学习,将我们的服务列表保持在一个阵列中
const[firstS,…restS]=[this.firstService,this.secondService,this.thirdService,this.fourthService,this.fifthService,this.sixthService];
const passValueToService=service=>result=>service.getThing(result.value);
passValueToService(firstS)(“first”).管道(
…restS.map(service=>mergeMap(passValueToService(service)))
).订阅(最终结果=>{
log(“结果六为:+finalResult.value”);
});
在嵌套subscribe调用时,这些简化都不是很容易完成的。但是,借助一些功能性的curry(以及方便的RxJS管道
组合),您可以开始看到您的选项显著扩展
理解concatMap
,mergeMap
,&switchMap
设置
我们将有3个助手函数,如下所述:
/****
*操作员:intervalArray
* -----------------------
*获取源发出的数组并将其空格隔开
*以毫秒为单位的给定间隔时间的值
****/
函数intervalArray(intervalTime=1000):运算符函数{
返回s=>s.pipe(
concatMap((v:T[])=>concat(
…v.map((值:T)=>EMPTY.pipe(
延迟(间隔时间),
startWith(值)
))
))
);
}
/****
*发射1、2、3,然后完成:每间隔0.5秒
****/
函数n123Stream():可观察{
返回([1,2,3])管道(
间隔阵列(500)
);
}
/****
*地图:
*1=>10,11,12,然后完成:每间隔1秒
*2=>20,21,22,然后完成:每间隔1秒
*3=>30,31,32,然后完成:每间隔1秒
****/
函数numberToStream(num):可观察{
返回([num*10,num*10+1,num*10+2])管道(
间隔阵列(1000)
);
}
上述映射函数(numberToStream
)负责concatMap
、mergeMap
和switchMap
订阅每个操作符
以下三段代码都有不同的输出:
n123Stream().管道(
concatMap(数字流)
).subscribe(console.log);
n123Stream().管道(
合并地图(数字流)
).subscribe(console.log);
n123Stream().管道(
开关映射(数字流)
).subscribe(console.log);
如果你