RxJs:多个请求后跟一个通过 concatMap 的请求不起作用
RxJs: multiple requests followed by one request via concatMap not working
我进行了一个 api 调用,其中 returns 一个数组。我需要遍历这个数组并为每个项目执行一个新请求。以下代码工作正常:
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
);
})
);
})
我也有一些稍微修改过的代码,但后来对数组中的每个项目执行了最终请求,它只需要执行一次。
有人知道如何解决这个问题吗?提前致谢!!
将 concatMap
之类的高阶运算符通过管道传输到来自 from
函数的流会为其源数组的每个元素触发它。您需要使用像 last
这样的运算符来将流限制为流中特定点的最后一个元素。
虽然管道 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
);
})
);
您可以使用 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... */)
);
Concat 方法
// 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$ 的末尾可能会很有用,因为这会导致 return 结果是条形码保存结果数组的元组和保存货件的结果。
这是我根据 Michael D 的回答得出的最终解决方案。最终的 concatMap 应该导致在 printViaIpAddress 方法中的每个项目的 subscribe 方法中命中成功方法。这非常有效。
Daniel 的回答最终导致每个串联的可观察对象都成功调用了方法(我认为),这在这种情况下并不是我想要的。
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,
});
})
);
})
);
我进行了一个 api 调用,其中 returns 一个数组。我需要遍历这个数组并为每个项目执行一个新请求。以下代码工作正常:
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
);
})
);
})
我也有一些稍微修改过的代码,但后来对数组中的每个项目执行了最终请求,它只需要执行一次。
有人知道如何解决这个问题吗?提前致谢!!
将
concatMap
之类的高阶运算符通过管道传输到来自from
函数的流会为其源数组的每个元素触发它。您需要使用像last
这样的运算符来将流限制为流中特定点的最后一个元素。虽然管道
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
);
})
);
您可以使用 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... */)
);
Concat 方法
// 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$ 的末尾可能会很有用,因为这会导致 return 结果是条形码保存结果数组的元组和保存货件的结果。
这是我根据 Michael D 的回答得出的最终解决方案。最终的 concatMap 应该导致在 printViaIpAddress 方法中的每个项目的 subscribe 方法中命中成功方法。这非常有效。
Daniel 的回答最终导致每个串联的可观察对象都成功调用了方法(我认为),这在这种情况下并不是我想要的。
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,
});
})
);
})
);