如何使用RxJs使用多个异步任务对批量操作进行管道和调优?
比如说如何使用RxJs使用多个异步任务对批量操作进行管道和调优?,rxjs,reactive-programming,Rxjs,Reactive Programming,比如说 购物车中有100种1-5个数量的产品,用户单击下订单 创建订单时,将执行以下任务: 以1对1的方式获取产品,以检查产品的可用性 检查并对每次购买10种产品的产品应用折扣 对每次购买50种产品的产品征收适用税 完成所有产品的计算后,计算订单总额 创建订单 注意:将产品添加到购物车时,可以向购物车添加多少物品是没有限制的,类似的任务也会在购物车中完成。我不完全确定您想要完成什么,但我想以下是您想要的: 假设以下是您的模型: 类产品{ id:编号; 名称:字符串; } 类产品订单{ 产品
- 购物车中有100种1-5个数量的产品,用户单击下订单
- 创建订单时,将执行以下任务:
- 以1对1的方式获取产品,以检查产品的可用性
- 检查并对每次购买10种产品的产品应用折扣
- 对每次购买50种产品的产品征收适用税
- 完成所有产品的计算后,计算订单总额
- 创建订单
注意:将产品添加到购物车时,可以向购物车添加多少物品是没有限制的,类似的任务也会在购物车中完成。我不完全确定您想要完成什么,但我想以下是您想要的: 假设以下是您的模型:
类产品{
id:编号;
名称:字符串;
}
类产品订单{
产品:产品;
数量:数量;
折扣:数量;
税种:数量;
}
阶级秩序{
productOrder:productOrder[];
总数:个;
}
考虑为每个步骤编写一个函数,其中每个函数的输入将是以前的输出:
/**
*检查产品的可用性,
*如果成功,则返回相同的@productOrder
*else抛出错误
*/
声明函数checkProductAvailability(productOrder:productOrder):可观察;
/**
*检查并应用产品折扣,
*将更改应用于@productOrder
*如果成功,则返回相同的@productOrder
*else抛出错误
*/
声明功能检查和应用折扣(productOrder:productOrder):可观察;
/**
*对产品征收适用税,
*将更改应用于@productOrder
*如果成功,则返回相同的@productOrder
*else抛出错误
*/
声明函数applyApplicableTaxes(productOrder:productOrder):可观察;
/**
*计算订单总数,
*如果成功返回@order
*else抛出错误
*/
声明函数CalculateOrderTotal(productOrder:productOrder[]):可观察;
/**
*创造秩序,
*如果成功回归
*else抛出错误
*/
声明函数createOrder(order:order):可观察;
具备上述功能后,剩下要做的就是将它们全部连接起来:
导入{
concatMap,
合并地图,
合并所有,
今天,
缓冲区计数,
捕捉错误,
}来自“rxjs/运营商”;
let productOrders:ProductOrder[];
来自(产品订单)
.烟斗(
concatMap(检查产品可用性),
缓冲计数(10),
mergeAll(),
concatMap(支票和应用折扣),
缓冲计数(50),
mergeAll(),
concatMap(适用于适用税),
toArray(),
合并映射(计算订单总数),
合并映射(createOrder),
catchError(errorHandler)
);
我已经制定了一个可能的解决方案,可以在中进行测试
这里是内嵌注释的逻辑
// this is the function that simulates a remote call to get the avalability of the
// quantity requested for a certain item
function checkAvailability(prodId: string, qty: number) {
// randomly decide if a product is available or not
const prodAvailable = Math.random() > 0
return of(prodAvailable)
}
// this is the function that simulates a call to get the discound for batches of 10 products
// at the time (the last batch can have less then 10 products)
function discount(prodIds: string[]) {
console.log('discount batch len', prodIds.length)
// discount is fixed to be 10%
const discounts = prodIds.map(p => 0.1)
return of(discounts)
}
// this function simulates a call to get the tax for arrays of max 50 products
function taxes(prodIds: string[]) {
console.log('taxes batch len', prodIds.length)
// taxes are fixed to be 20%
const taxes = prodIds.map(p => 0.2)
return of(taxes)
}
// build the initial cart which contains 100 items - each item contains the product id
// the quantity and the price (quantity and price as set to 1)
let cart: {prodId: string, qty: number, price: number}[] = new Array(100).fill(null)
cart = cart.map((_, i) => ({prodId: 'p' + i, qty: 1, price: 1}))
// this is the function that returns an Observabel which notifies the total of the order
function orderTotal$(cart: {
prodId: string;
qty: number;
price: number;
}[]) {
// first we create a stream of items in the cart
return from(cart).pipe(
// for each item we call the function which returns the availability of the item
// since the availability is calculated by an aync service, we use mergeeMap
mergeMap(({prodId, qty, price}) => checkAvailability(prodId, qty).pipe(
// we need to return not only the availability but also the rest of the data
// so we pipe this map operator to enrich the data passed back
map(available => ({available, prodId, qty, price}))
)),
// we filter only the available products
filter(({available, prodId, qty}) => available),
// buffer the items available in budders of 10
bufferCount(10),
// use mergeMap, as we do above, to retrieve the discount from the remote async service
mergeMap(ar => {
// return an object enriched wit the discound info
return discount(ar.map(item => item.prodId)).pipe(
map(discs => discs.map((disc, i) => ({...ar[i], disc})))
)
}),
// use this merge mergeMap to tranform the emissions of batches of items with length 10
// into a stream of 10 items
mergeMap(ar => ar),
// now create batched with size 50
bufferCount(50),
// use mergeMap to invoKe the remote service which returns the taxes
mergeMap(ar => {
const pIds = ar.map(item => item.prodId)
return taxes(pIds).pipe(
map(txs => txs.map((tax, i) => ({...ar[i], tax})))
)
}),
// again use mergeMap to generare a strea of 50 items
mergeMap(ar => ar),
// use reduce to calculate the order total
reduce((orderTotal, item) => {
const itemPrice = item.price
orderTotal = orderTotal + (itemPrice - itemPrice * item.disc + itemPrice * item.tax) * item.qty
return orderTotal
}, 0)
)
}
// subscribe to the result of orderTotal$ function to get the total of the orer
orderTotal$(cart).subscribe(d => console.log('order total', d))
这里的异步任务是什么?你能告诉我们你已经尝试过的代码以及你到底坚持到了哪里吗?RxJx新手,所以我想知道如果CheckAndApply折扣需要50个项目,ApplyAppliedTaxes需要10个项目,我该如何实现?请记住,在一天结束时,我们要处理流,一次处理一个项目,bufferCount用于等待特定数量的发射到达,然后让流继续流动