【问题标题】:RxJS & Angular HttpClient: How to transform value asynchronously?RxJS 和 Angular HttpClient:如何异步转换值?
【发布时间】:2017-12-07 19:28:00
【问题描述】:

我想对 observable 发出的值应用异步转换函数。

@Injectable
export class ApiService{
    constructor(private http: HttpClient){}

    getSomething(url): Observable<any>{
        return this.http.get(url);
    }
}

在上面的代码中,我想在this.http.get(url) 发出的值上应用一个转换函数myFunc,它返回一个promise。

通常我会使用 RxJS 的 map 操作符,但是由于转换函数返回一个 promise,我找不到处理它的方法。

例如,让我的函数为:

function myFunc(value){
    return new Promise((resolve, reject) => {
        // modify the value async

        resolve(modifiedValue);

        // ...
    });
}

有没有合适的方法来处理这个任务?我认为以下不合适,对吗?

return this.http.get(url).map(myFunc);

任何帮助将不胜感激。

注意:我使用的是 RxJS 5.5.2

【问题讨论】:

  • 是什么让你觉得它不合适?你试过了吗?发生了什么?
  • 是的,我试过了。我收到的价值与我预期的有些不同。我得到了一个像{__zone_symbol__state: true, __zone_symbol__value : x} 这样的对象,其中 x 是我所期望的,但正如您所见,它被包裹在另一个对象中。我不知道那些区域符号是什么 :)
  • 那么显示minimal reproducible example可能会有所帮助,目前还不清楚问题出在哪里。
  • 为了澄清你的问题,我相信你是说你的映射函数是异步的(返回一个承诺),所以你不能使用 map 运算符。您可以更改映射函数以返回一个可观察对象,然后使用 switchMap 运算符而不是 map 吗?为什么你的映射函数是异步的?
  • 好的,也许你可以这样做:return this.http.get(url).switchMap(x =&gt; Observable.fromPromise(myFunc(x)));

标签: javascript angular rxjs rxjs5


【解决方案1】:

使用mergeMap操作符获取响应值,通过另一个Observable操作异步进行一些修改,然后返回修改后的值。此运算符将合并 HttpClient 发出的值和您的修饰符 Observable 并返回一个发出变异值的 Observable。

编辑:包括@bygrace 评论中的Observable.fromPromise 位以获得更完整的答案。

编辑:适用于 RxJs v5.5+

import { pipe } from 'rxjs/util/pipe';
import { mergeMap } from 'rxjs/operators';


    @Injectable
    export class ApiService{
        constructor(private http: HttpClient){}

        getSomething(url): Observable<any>{
            return this.http.get(url).pipe( 
                                        mergeMap(myFunc) 
                                      );
        }

        private myFunc(x): Observable<any> {
            // do some asynchronous modification that returns an Observable
            return Observable.fromPromise(x);
        }
    }

Pre RxJs v5.5

@Injectable
export class ApiService{
    constructor(private http: HttpClient){}

    getSomething(url): Observable<any>{
        return this.http.get(url)
               .mergeMap(data => {
                   // do some asynchronous modification that returns an Observable
                   return Observable.fromPromise(data);
                });
    }
}

见:http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-mergeMap

【讨论】:

  • 感谢您的回答。但我想坚持观察而不是返回承诺。因为ApiService的消费者会对getSomething方法返回的对象调用subscribe。
  • 对不起,我误解了你的目标。我看到有人建议使用switchMap,它产生与mergeMap 相同的输出。唯一的区别是他们在内部使用了不同的运算符。
  • @rawkfist0215 澄清mergeMapflatMap 是相同的。 switchMap 只维护一个内部订阅,而mergeMap 维护多个。所以有一个微妙的区别需要注意。如果您想在源发出时取消由内部可观察对象生成的请求,则基本上使用switchMap
  • @rawkfist0215 我也想试试mergeMap。但我收到以下 tslint 错误:property 'mergeMap' does not exist on type 'Observable&lt;any&gt;' 即使我从“rxjs/operators”导入了 mergeMap。有想法吗?
  • @hswner 如果您使用的是足够高的 RxJs 版本,您可能想尝试使用 pipe util 运算符,看看是否可以清除 tslint 错误。这是他们新推荐的最佳实践。见:github.com/ReactiveX/rxjs/blob/master/doc/lettable-operators.md
猜你喜欢
  • 2022-01-16
  • 2021-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多