简体   繁体   English

如何在高阶可观察量中返回外部可观察量而不是内部可观察量

[英]How to return outer observable and not inner in a High-order observables

Lets clarify the problem with the following code:让我们用以下代码澄清问题:

    this.rates$ = this._glbRateService.getRates(params); // 1
    this.rates$.pipe(
        mergeMap(rates => {
            const priceByRates: Observable<any>[] = rates.map(rate => {
                const paramsRatingItemProduct = {
                    idItem: product.idItem,
                    idRate: rate.idRate
                };
                return this._glbRatingItemProduct.getPrice(paramsRatingItemProduct); // 2
            });
            return priceByRates;
        })
    ).subscribe(response => {
        console.log(response); // 3
    });

In that code:在该代码中:

  1. I get rates from server我从服务器获取费率
  2. For every rate, I get prices (map)对于每个费率,我都会得到价格(地图)
  3. My console.log returns the value from the inner subscription (this._glbRatingItemProduct.getPr...)我的 console.log 返回内部订阅的值(this._glbRatingItemProduct.getPr ...)

And what I want is to do logic with the mapping values and the inner subscription.我想要的是对映射值和内部订阅进行逻辑处理。

Something like this:像这样:

this.rates$ = this._glbRateService.getRates(params);
this.rates$.pipe(
    mergeMap(rates => {
        const priceByRates: Observable<any>[] = rates.map(rate => {
            const paramsRatingItemProduct = {
                idItem: product.idItem,
                idRate: rate.idRate
            };
            return this._glbRatingItemProduct.getPrice(paramsRatingItemProduct);
            // WITH THE SUBSCRIPTION OF THIS RETURN I WANT TO MAKE LOGIC
            // WITH rates.map, and then return rates, NOT THE INNER SUBSCRIPTION

        });
        return priceByRates;
    })
).subscribe(response => {
    console.log(response);
});

You first need to execute the inner observable array first with maybe forkJoin then run your mapping function with the array您首先需要先使用forkJoin执行内部可观察数组,然后使用该数组运行映射 function

mergeMap(rates => {
    const priceByRates: Observable<any>[] = rates.map(rate => {
        const paramsRatingItemProduct = {
            idItem: product.idItem,
            idRate: rate.idRate
        };
        return this._glbRatingItemProduct.getPrice(paramsRatingItemProduct);

    });
    return forkJoin(...priceByRates).pipe((values)=>values.map....your logic ));
})

https://www.learnrxjs.io/learn-rxjs/operators/combination/forkjoin https://www.learnrxjs.io/learn-rxjs/operators/combination/forkjoin

It's sometimes helpful to separate out the logic of mapping and flattening higher-order observables.有时将映射和展平高阶可观察量的逻辑分开是有帮助的。 Here it should be a bit clearer that map() returns an array of observables and forkJoin() joins all those observables into one stream.这里应该更清楚一点, map()返回一组可观察值, forkJoin()将所有这些可观察值连接成一个 stream。

this.rates$ = this._glbRateService.getRates(params);
this.rates$.pipe(
  map(rates => rates.map(
    rate => this._glbRatingItemProduct.getPrice({
      idItem: product.idItem,
      idRate: rate.idRate
    })
  ),
  mergeMap(priceByRates => forkJoin(priceByRates))
).subscribe(console.log);

On the other hand, forkJoin() only emits once all source observables complete.另一方面, forkJoin()仅在所有源可观察对象完成后才发出。 If you don't need all the responses together, you keep your source streams de-coupled with a simpler merge() .如果您不需要将所有响应放在一起,则可以使用更简单的merge()使源流分离。 Only one line needs to change:只有一行需要更改:

mergeMap(priceByRates => merge(...priceByRates))

The thing to remember is that mergeMap expects a single stream to be returned.要记住的是mergeMap期望返回一个 stream。 It will convert an array into a stream of values.它将一个数组转换为 stream 个值。 So mergeMap(num => [10,9,8,7,num]) doesn't map num into an array, it creates a new stream that will emit those numbers one at a time.所以mergeMap(num => [10,9,8,7,num])不会将 map num放入一个数组中,它会创建一个新的 stream,它将一次一个地发出这些数字。

That's why mergeMap(_ => val: Observable[]) will just emit each observable, (as a higher order observable) one at a time.这就是为什么mergeMap(_ => val: Observable[])只会一次发出每个可观察对象(作为高阶可观察对象)。

With this knowledge, you can actually change your stream to merge without using the static merge function above.有了这些知识,你其实可以把你的 stream 改成 merge 而不用上面的 static merge function。 That could look like this:这可能看起来像这样:

this.rates$ = this._glbRateService.getRates(params);
this.rates$.pipe(
  mergeMap(rates => rates.map(
    rate => this._glbRatingItemProduct.getPrice({
      idItem: product.idItem,
      idRate: rate.idRate
    })
  ),
  mergeAll()
).subscribe(console.log);

mergeAll() will take each higher-order observable as it arrives and subscribe+merge their output. mergeAll() 将接收每个到达的高阶可观察对象并订阅+合并它们的 output。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM