RxJS subscribe inside subscribe with each level re

2020-04-19 06:27发布

问题:

I know already there are posts regarding the Nested Subscribe. Here, we have 5 leveled subscribeoperation with each variables (operationId,actionlistId,componentId,traceId). Here Apis are calling whose function is given below.

Step 1: orderTemplateId to api GetOperationTemplate, will get values operationModel and operationId.
Step 2: operationId to api GetActionTemplate, will get values actionId, actionListId and actionModel.
Step 3: actionId to api GetComponentUsageTemplate, will get values componentId and componentModel.
Step 4: componentId/ to api GetTraceTemplate, will get values traceId and traceModel.

OLD WORKING CODE Which is causing delay.

  onOrderTemplateClick(selectedData: any): void {
    this.selectedData = selectedData;
    this.descOrderTemplate = selectedData.name;
    this.orderTemplateId = selectedData.id;
    this.orderTemplateFormGroup.controls['orderTemplate'].setValue(this.descOrderTemplate);
    console.log('OperationTemplate');

    this.ordertemplateService.GetOperationTemplate(this.orderTemplateId)
     .subscribe((res: any) => {
        this.operationModel = res;
        if (Object.keys(this.operationModel).length > 0) {
          console.log(this.operationModel);
          console.log('ActionList');
          this.ordertemplateService.GetActionTemplate(this.operationModel[0].id)
             .subscribe((res1: any) => {
              this.actionModel = res1;

              if (Object.keys(this.actionModel).length > 0) {
                this.actionId = res1[0].id;
                this.actionListId = res1[0].parentId;
                console.log(this.actionModel);
                console.log('Action Parameters');

                this.ordertemplateService.GetActionParameterTemplate(this.actionModel[0].parentId)
                 .subscribe((res2: any) => {
                    if (Object.keys(res2).length > 0) {
                      this.actionParamModel = res2;
                      this.actionParameterId = res2[0].id;
                      this.actionParameterId = this.actionParamModel[0].id;
                    } else {
                      this.initializeActionParameterComponentTrace();
                    }
                  });

                console.log('Component Usage');
                this.ordertemplateService.GetComponentUsageTemplate(this.actionModel[0].id)
                 .subscribe((res3: any) => {
                    this.componentModel = res3;
                    this.componentId = res3[0].id;
                    if (Object.keys(this.componentModel).length > 0) {
                      console.log(this.componentModel);
                      console.log('Component Usage');
                      this.ordertemplateService.GetTraceTemplate(this.componentModel[0].parentId)
                        .subscribe((res4: any) => {
                          this.traceModel = res4;
                          if (Object.keys(this.traceModel).length > 0) {
                            this.traceId = res4[0].id;
                            console.log(this.traceModel);
                            console.log('Trace Usage');
                          } else {
                            this.initializeTrace();
                          }

                        });
                    } else {
                      this.traceActions(this.actionModel[0].id);

                    }
                  });


              } else {
                this.initializeComponentTrace();
              }
            }
            );
        } else {
          this.initializeAll();
        }


      });
  }

NEW WORKING CODE which I am trying using switchmap.

 onOrderTemplateClick(selectedData: any): void {
    this.selectedData = selectedData;
    this.descOrderTemplate = selectedData.name;
    this.orderTemplateId = selectedData.id;
    this.orderTemplateFormGroup.controls['orderTemplate'].setValue(this.descOrderTemplate);
    console.log('OperationTemplate');
    this.ordertemplateService.GetOperationTemplate(this.orderTemplateId)
    .pipe(
    switchMap((opData)=> {        
            this.operationModel = opData;
            if (Object.keys(this.operationModel).length > 0) {
              console.log(this.operationModel);
        } else {
                    this.initializeAll();
                }
        }),
    switchMap((actData)=> {
        console.log('ActionList');
            this.actionModel=this.ordertemplateService.GetActionTemplate(this.operationModel[0].id); // actdata[0].id
         if (Object.keys(this.actionModel).length > 0) {
                    this.actionId = this.actionModel[0].id;
                    this.actionListId = this.actionModel[0].parentId;
                    console.log(this.actionModel);
            console.log('Action Parameters');
                    this.actionParamModel = this.ordertemplateService.GetActionParameterTemplate(this.actionModel[0].parentId);
            if (Object.keys(this.actionModel).length > 0) {
            this.actionParameterId = this.actionParamModel[0].id;
            console.log(this.actionParamModel);
            } else {
            this.initializeActionComponentTrace();
            }       
        } else {
                    this.initializeActinonactionParameterComponentTrace();
                }
        }),
    switchMap((cmpData)=> {
        console.log('Component Usage');
        this.componentModel = this.ordertemplateService.GetComponentUsageTemplate(this.actionModel[0].id); // cmpData[0].id
        this.componentId = this.componentModel[0].id;
        if (Object.keys(this.componentModel).length > 0) {
                      console.log(this.componentModel);
                      console.log('Component Usage');
        } else {
                    this.initializeComponentTrace();
                }       
        }),
    switchMap((traceData)=> {
        this.traceModel = this.ordertemplateService.GetTraceTemplate(this.componentModel[0].parentId); // cmpData[0].id
                if (Object.keys(this.traceModel).length > 0) {
                     this.traceId = this.traceModel[0].id;
                     console.log(this.traceModel);
                     console.log('Trace Usage')
         } else {
                     this.initializeTrace();
                 }

    }))
    .subscribe((data)=> {
        if(data!= undefined) {
        console.log(data);
        }
  })
}

The below code causes delay of 10 sec(max). Is Nested Subscribe related to delay?

回答1:

Generally, there is nothing wrong with your code (I am referring to your updated code). However, I do realise that within each switchMap() operator sequence, you aren't really emitting any new observable values, hence that isn't really the right way to use RxJs's switchMap() operator.

As described on the documentation, switchMap allows you to

Map to observable, complete previous inner observable, emit values.

Therefore, it might be more appropriate to use the tap operator, as you are merely performing side effects in sequence, and returning to source observable at the end of the chain when you subscribe to it.

onOrderTemplateClick(selectedData: any): void {
  this.selectedData = selectedData;
  this.descOrderTemplate = selectedData.name;
  this.orderTemplateId = selectedData.id;
  this.orderTemplateFormGroup.controls['orderTemplate'].setValue(this.descOrderTemplate);
  console.log('OperationTemplate');
  this.ordertemplateService.GetOperationTemplate(this.orderTemplateId)
    .pipe(
      tap((opData) => {
        this.operationModel = opData;
        if (Object.keys(this.operationModel).length > 0) {
          console.log(this.operationModel);
        } else {
          this.initializeAll();
        }
      }),
      tap((actData) => {
        console.log('ActionList');
        this.actionModel = this.ordertemplateService.GetActionTemplate(this.operationModel[0].id); // actdata[0].id
        if (Object.keys(this.actionModel).length > 0) {
          this.actionId = this.actionModel[0].id;
          this.actionListId = this.actionModel[0].parentId;
          console.log(this.actionModel);
          console.log('Action Parameters');
          this.actionParamModel = this.ordertemplateService.GetActionParameterTemplate(this.actionModel[0].parentId);
          if (Object.keys(this.actionModel).length > 0) {
            this.actionParameterId = this.actionParamModel[0].id;
            console.log(this.actionParamModel);
          } else {
            this.initializeActionComponentTrace();
          }
        } else {
          this.initializeActinonactionParameterComponentTrace();
        }
      }),
      tap((cmpData) => {
        console.log('Component Usage');
        this.componentModel = this.ordertemplateService.GetComponentUsageTemplate(this.actionModel[0].id); // cmpData[0].id
        this.componentId = this.componentModel[0].id;
        if (Object.keys(this.componentModel).length > 0) {
          console.log(this.componentModel);
          console.log('Component Usage');
        } else {
          this.initializeComponentTrace();
        }
      }),
      tap((traceData) => {
        this.traceModel = this.ordertemplateService.GetTraceTemplate(this.componentModel[0].parentId); // cmpData[0].id
        if (Object.keys(this.traceModel).length > 0) {
          this.traceId = this.traceModel[0].id;
          console.log(this.traceModel);
          console.log('Trace Usage')
        } else {
          this.initializeTrace();
        }

      }))
    .subscribe((data) => {
      if (data != undefined) {
        console.log(data);
      }
    })
}

With regards to the delay, that is probably because it is quite a long sequence, and that you are invoking quite a number of operations, which is why it takes a long time to finish running it. I would recommend you to remove any function calls that do not require it to be run in sequence, and call them outside the observable flow.



回答2:

Your code looks correct. So you need to figure out what part of code gets so many time. I suggest you to use performance.now() method to measure your code:

console.log(`1. performance.now() ${performance.now()}`);
this.ordertemplateService.GetOperationTemplate(this.orderTemplateId)
.pipe(
switchMap((opData)=> {        
    console.log(`2. performance.now() ${performance.now()}`);
    }),
switchMap((actData)=> {
    console.log('ActionList');

switchMap((cmpData)=> {
    console.log(`3. performance.now() ${performance.now()}`);
    this.componentModel = this.ordertemplateService.GetComponentUsageTemplate(this.actionModel[0].id); // cmpData[0].id
    this.componentId = this.componentModel[0].id;
    if (Object.keys(this.componentModel).length > 0) {
                  console.log(this.componentModel);
                  console.log('Component Usage');
    } else {
                this.initializeComponentTrace();
            }       
    console.log(`4. performance.now() ${performance.now()}`);
    }),
switchMap((traceData)=> {
    console.log(`5. performance.now() ${performance.now()}`);
    this.traceModel = this.ordertemplateService.GetTraceTemplate(this.componentModel[0].parentId); // cmpData[0].id
            if (Object.keys(this.traceModel).length > 0) {
                 this.traceId = this.traceModel[0].id;
                 console.log(this.traceModel);
                 console.log('Trace Usage')
     } else {
                 this.initializeTrace();
             }

    console.log(`6. performance.now() ${performance.now()}`);
}))
.subscribe((data)=> {
    if(data!= undefined) {
    console.log(data);
    console.log(`7. performance.now() ${performance.now()}`);
    }
})

Then you will have an iformation, what piece of code is takes so many time.



标签: angular rxjs