RxJS - 如果满足某些条件,则跳过功能

时间:2017-05-16 08:12:02

标签: angular typescript rxjs

在我正在开发的Angular Web-Application中,我需要使用Observable来做很多事情。
通常Observable用于异步事件序列,但是,对我来说,通常只有1个结果(来自http请求)。
我经常需要做一些复杂的映射,以从http请求中获得所需的结果。但是,只有满足某些条件时才需要此映射,否则我可以跳过整个映射部分并返回默认值 例如:
我想获得给定article中特定city的销售总额 获得结果需要以下步骤:

  1. 获取所有client s,其中包含city city.getClients():Observable<Array<Client>>http GET - &gt; Observable<Array<Client>>
  2. 确定每article个给定client的销售额 (flatMap - &gt; Observable<Array<ClientSale>>
  3. 获取每article个给定client的总销售额 (map - &gt; Observable<Array<number>>
  4. 总结一下 (map - &gt; Observable<number>
  5. 现在有可能,那个城市没有client生活 在这种情况下,可以跳过步骤2-4,并且可以使用值onNext调用0 - 回调。

    请注意,这只是一个简单的例子,用于解释我想要做的事情。真正的用例需要更多步骤,我需要做一个

    if (meetsCondition(x))
        return map(x);
    else
        return defaultValue;
    

    每一步。

    filter - 函数几乎就是我要找的。但是,它不会为过滤后的值调用onNext

    有没有办法实现我想要的目标?

    修改
    我将尝试在问题中添加更多细节:
    我的应用程序中有很多延迟加载的数据。因此,如果您请求city,则无法加载相关的client,直到您通过调用getClients请求它们为止。 因此,大多数getter返回Observable数据而不是数据本身。

    现在我经常需要通过组合不同来源的值(clientarticle等)来计算事物。
    通常这种计算可以在中间停止,因为无法确定有效结果 如果值为空,则可能是这种情况,但如果筛选的列表包含多个条目,则也是如此。

    如果我能够做到这样的话,那么对我来说完美的解决方案就是:

    client.getOrders()
       .skipIf(value => !meetsCondition(value), defaultValue)
       .map(value => mapValue(value))        // Probably not called
       .map(value => mapValueAgain(value))   // Probably not called
       .subscribe(value => {
            if (value == defaultValue)
                console.log("Skip");
            else
                console.log(value)
       });
    

1 个答案:

答案 0 :(得分:2)

我构建了你的案例,如下所示。正确?

function getClients(city:string) {
    return Observable.of(city == 'Seoul' ? ['c1', 'c2'] : []).delay(100);
}
function getSales(client:string, article:string) {
    let sales:any = {
        'c1': {
            'item1': 10,
            'item2': 20
        },
        'c2': {
            'item1': 30,
            'item2': 40
        }
    };

    return Observable.of(sales[client][article]).delay(100);
}

let city = 'Seoul';
let article = 'item2';

getClients(city)
    .mergeMap(clients => {
        console.log('>> mergeMap');
        let salesObs = clients.map<Observable<number>>(client => getSales(client, article));
        return Observable.merge(salesObs).mergeAll();
    })
    .reduce((sum, sales) => {
        console.log('>> reduce');
        return sum + sales;
    }, 0)
    .subscribe(value => console.log(`sum = ${value}`));

虽然在这种情况下客户端为空,但没有问题。将城市更改为其他值并尝试。

我添加了一些代码,以便在一般情况下使用&#39; map&#39;并且&#39;赶上&#39; 如果它符合某些跳过条件,那么&#39; mergeMap&#39;并且&#39;减少&#39;没有被解雇。

getClients(city)
    .map(clients => {
        // some skip condition
        if (clients.length == 0)
            throw 0 /* default value */;

        return clients;
    })
    .mergeMap(clients => {
        console.log('>> mergeMap');
        let salesObs = clients.map<Observable<number>>(client => getSales(client, article));
        return Observable.merge(salesObs).mergeAll();
    })
    .reduce((sum, sales) => {
        console.log('>> reduce');
        return sum + sales;
    }, 0)
    .catch((err, caught) => {
        console.log('>> catch');
        // default value
        return Observable.of(err);
    })
    .subscribe(value => console.log(`sum = ${value}`));