1

我进行了一个返回数组的 api 调用。我需要遍历这个数组并为每个项目执行一个新请求。以下代码工作正常:

return this.expeditionService.getTranssmartBookingXml(request).pipe(
  concatMap((response) => {
    return from(response.barcodes).pipe(
      concatMap((barcode) => {
        return this.expeditionService.saveTranssmartBarcode({
          ...saveBarcodeRequest,
          barcode: barcode,
        });
      })
    );
  })
);

但是,当所有项目都完成后,我想提出另一个请求。只有一个。

但是当我使用以下代码时,当 from 数组中的第一项完成时,该过程停止。

return this.expeditionService.getTranssmartBookingXml(request).pipe(
  concatMap((response) => {
    return from(response.barcodes).pipe(
      concatMap((barcode) => {
        return this.expeditionService.saveTranssmartBarcode({
          ...saveBarcodeRequest,
          barcode: barcode,
        });
      }),
      concatMap(() => {
        const transsmartSaveShipmentRequest: TranssmartSaveShipmentRequest =
          {
            reference: this.shipmentReferenceResult!.reference,
            price: this.transsmartDoBookingResponse!.price,
            trackingUrl: this.transsmartDoBookingResponse!.trackingUrl,
          };

        return this.expeditionService.saveTranssmartShipment(
          transsmartSaveShipmentRequest
        );
      })
    );
  })

我也有一些稍微修改过的代码在它工作的地方,但是最后的请求是为数组中的每个项目执行的,它只需要执行一次。

有人知道如何解决这个问题吗?提前致谢!!

4

3 回答 3

1
  1. 将高阶运算符(例如concatMap来自from函数的流)通过管道传递给它的源数组的每个元素都会触发它。您需要使用类似操作符last将流限制为流的特定点的最后一个元素。

  2. 虽然它不会last对内部或外部 observable 管道产生影响,但我更喜欢将它管道到外部 observable,因为它看起来更优雅。

return this.expeditionService.getTranssmartBookingXml(request).pipe(
  concatMap((response) => {
    return from(response.barcodes).pipe(
      concatMap((barcode) => {
        return this.expeditionService.saveTranssmartBarcode({
          ...saveBarcodeRequest,
          barcode: barcode,
        });
      })
    )
  }),
  last(),
  concatMap(() => {
    const transsmartSaveShipmentRequest: TranssmartSaveShipmentRequest = {
      reference: this.shipmentReferenceResult!.reference,
      price: this.transsmartDoBookingResponse!.price,
      trackingUrl: this.transsmartDoBookingResponse!.trackingUrl,
    };

    return this.expeditionService.saveTranssmartShipment(
      transsmartSaveShipmentRequest
    );
  })
);
于 2021-12-06T13:07:23.597 回答
1

您可以使用toArray将一堆单独的发射组合成一个数组,或者您可以使用concat只处理两个可观察的串行,因为您似乎真的不想要保存条形码的结果。

我更喜欢第二种,但两者都希望你想要并且看起来比你拥有的更干净。

ToArray 方法

return this.expeditionService.getTranssmartBookingXml(request).pipe(
  concatMap(res => from(res.barcodes)),
  concatMap(barcode => this.expeditionService.saveTranssmartBarcode({
    ...saveBarcodeRequest,
    barcode
  })),
  toArray(),
  concatMap(() => /* save TrannsmartShipmentRequest... */)
);

连接方法

// you don't have to create variables as you can place the streams directly in concat.
const saveBarCodes$ = this.expeditionService.getTranssmartBookingXml(request).pipe(
  concatMap(res => from(res.barcodes)),
  concatMap(barcode => this.expeditionService.saveTranssmartBarcode({
    ...saveBarcodeRequest,
    barcode
  }))
);
// no point in this being inside an operator.
const saveShipmentRequest: TranssmartSaveShipmentRequest = {
  reference: this.shipmentReferenceResult!.reference,
  price: this.transsmartDoBookingResponse!.price,
  trackingUrl: this.transsmartDoBookingResponse!.trackingUrl
};
const saveShipment$ = this.expeditionService.saveTranssmartShipment(saveShipmentRequest);
return concat(saveBarCodes$, saveShipment$);

如果将toArray添加到saveBarCode$的末尾可能会很有用,因为这会导致返回结果是条形码保存结果数组和保存货件的结果的元组。

于 2021-12-06T14:50:29.027 回答
0

这是我基于 Michael D 的回答的最终解决方案。最终的 concatMap 应该导致在 printViaIpAddress 方法中的每个项目的 subscribe 方法中点击成功方法。这完美地工作。

Daniel 的回答最终导致每个连接的 observable(我认为)都达到了成功方法,这并不是我在这种情况下想要的。

return this.expeditionService.getTranssmartBookingXml(request).pipe(
  concatMap((response) => {
    saveShipmentRequest.price = response.price;
    saveShipmentRequest.trackingUrl = response.trackingUrl;

    return from(response.barcodes).pipe(
      concatMap((barcode) => {
        return this.expeditionService.saveTranssmartBarcode({
          ...saveBarcodeRequest,
          barcode: barcode,
        });
      })
    );
  }),
  last(),
  concatMap(() => {
    return this.expeditionService.saveTranssmartShipment(
      saveShipmentRequest
    );
  }),
  concatMap(() => {
    return this.expeditionService.getTranssmartLabels(
      transsmartBonnenXmlRequest
    );
  }),
  concatMap((response) => {
    return from(response.values).pipe(
      concatMap((label) => {
        return this.expeditionService.printViaIpAddress({
          ...printTranssmartRequest,
          label,
        });
      })
    );
  })
);
于 2021-12-07T09:37:16.243 回答