Angular RXJS 顺序多重 post 请求

Angular RXJS Sequential multiple post request

我尝试使用 concat 映射执行以下功能。但我不确定正确的方法是什么。

//Req 01
await this.shippingInfoService.getShipmentInfoByCardId(this.data.CardId).then(async (shipmentData) => {
      if (shipmentData != undefined) {
        if (shipmentData.ShipmentId !== null && shipmentData.ShipmentId !== "") {
          //If shipment is assigned
          let shipmentId = shipmentData.ShipmentId;
          let contract = JSON.parse(sessionStorage.getItem(SITE_DETAILS_KEY)).Contract;

          let printObj = {
            "ShipmentId": Number(shipmentId),
            "Contract": contract
          }

//Second Req
          await this.orderDetailsService.printBillOfLading(printObj).then(async () => {
            await this.orderDetailsService.getBillOfLeadingPdfInfo(shipmentId).then(async (response) => {
              if (response.ResultKey === null || response.Id === null) {
                const dialogConfig = new MatDialogConfig();
                dialogConfig.data = "The information needed to generate a report isn't available.";
                dialogConfig.disableClose = true;
                this.dialog.open(ErrorDialogComponent, dialogConfig);
                //Hide Loading indicator
                this.store.dispatch(setLoadingSpinner({showLoading: false}));
              } else {
// 3rd Req
                let url = await this.orderDetailsService.generateBillOfLadingPdfUrl(response.ResultKey, response.Id);
                await window.open(url.url, "_blank");
                //Hide Loading indicator
                await this.store.dispatch(setLoadingSpinner({showLoading: false}));
              }
            });
          });
        } else {
          //If shipment is not assigned
          //Hide Loading indicator
          this.store.dispatch(setLoadingSpinner({showLoading: false}));
          //Error
          const dialogConfig = new MatDialogConfig();
          dialogConfig.data = "Shipment needs to be connected";
          dialogConfig.disableClose = true;
          this.dialog.open(ErrorDialogComponent, dialogConfig);
        }
      }
    })
  1. 请求 02 依赖于请求 01
  2. 请求 03 依赖于请求 02

需要用 rxjs 运算符重构上面的代码。

这是对您的代码的重构,尽可能少地更改(在一定程度上)。我不认为这是编写 RxJS 最惯用的方式,但我也不会像上面那样编写 Promises。

我无法测试任何这些,所以这是答案的 形状 ,而不是答案本身。也许它会让你开始...

祝你好运:

//Req 01
from(this.shippingInfoService.getShipmentInfoByCardId(this.data.CardId)).pipe(
  filter(shipmentData => shipmentData != undefined),
  tap(shipmentData => {
    if (shipmentData.ShipmentId !== null && shipmentData.ShipmentId !== "") {
      throw "Shipment needs to be connected"
    }
  }),
  // Second Req because shipment is assigned
  concatMap(shipmentData => this.orderDetailsService.printBillOfLading({
      "ShipmentId": Number(shipmentData.ShipmentId),
      "Contract": JSON.parse(sessionStorage.getItem(SITE_DETAILS_KEY)).Contract
    }).pipe(
      map(_ => Number(shipmentData.ShipmentId))
    )
  ),
  concatMap(id => this.orderDetailsService.getBillOfLeadingPdfInfo(id)),
  tap(response => {
    if ( response.ResultKey === null || response.Id === null) {
      throw "The information needed to generate a report isn't available."
    }
  }),
  // 3rd Req
  concatMap(response =>
    this.orderDetailsService.generateBillOfLadingPdfUrl(response.ResultKey, response.Id)
  ),
  // Catch errors thrown above
  catchError(error => {
    // This isn't really comprehensive error management for obvious reasons. 
    // I'm assuming the only errors are one of the two strings thrown above.
    const dialogConfig = new MatDialogConfig();
    dialogConfig.data = error;
    dialogConfig.disableClose = true;
    this.dialog.open(ErrorDialogComponent, dialogConfig);

    // Returning empty means we don't propogate this error
    return EMPTY;
  }),
  // Always finish by Hiding Loading indicator
  finalize(() => this.store.dispatch(setLoadingSpinner({showLoading: false})))
).subscribe(
  url => window.open(url.url, "_blank")
);
  1. 并非所有内容都必须是匿名内联函数,并且 2) 函数可以 return 某些东西。序列的一般形状看起来或多或少是这样的:
getShipmentInfo().pipe(
    map(response => parseShipmentData(response)),
    switchMap(printObj => forkJoin([
// Why do them in sequence? You aren't using results from `printBillOfLading` for anything
        printInvoice(printObj),
        getPdfInfo(printObj.ShipmentId),
    ]),
    switchMap(([nevermind, pdfResponse]) => handlePdfResponse(pdfResponse))
)

parseShipmentDataprintInvoicegetPdfInfohandlePdfResponse 填充了原始代码中的相关逻辑片段。顺便说一句,将 awaitthen 混合并嵌套 async 函数是不必要的,只会混淆您的代码。