简体   繁体   English

使用RxJS从订阅中返回Observable

[英]Return a Observable from a Subscription with RxJS

I currently have a service that do a HTTP request to an API to fetch data. 我目前有一项服务,它向API发送HTTP请求以获取数据。 There are some logic that I want to do to the observable from within the service, but I still want to also subscribe to the Observable in my Component so that I can return any errors to the Component and to the user. 我想从服务中对observable做一些逻辑,但我仍然想在我的Component中订阅Observable,这样我就可以将任何错误返回给Component和用户。

Currently I do: 目前我这样做:

// service.ts
getData(): Observable<any> {
    return this.http.get(url).pipe(catchError(this.handleError)
}

// component.ts
ngOnInit() {
    this.service.getData().subscribe(res => {
        // Do my logic that belong to the service.ts
        // ...

        // Do my logic that belongs in the component.ts
        // ...
    }, err => this.errors = err)
}

What I would like to do is to refactor this so that I handle the logic related to the subscription and the service.ts within the getData() method, and then return an Observable with the HTTP response and any errors to the Component so that I can continue doing things there. 我想要做的是重构这个,以便我在getData()方法中处理与订阅和service.ts相关的逻辑,然后返回一个带有HTTP响应和任何错误的Observable到Component,这样我就可以了可以继续在那里做事。

What's the pattern to do this? 这样做的模式是什么?

I feel like multiple of the patterns and solutions posted is "ugly" or does not follow the Observable pattern (Like doing callbacks). 我觉得发布的模式和解决方案的多个是“丑陋的”或者不遵循Observable模式(就像做回调一样)。

The cleanest, most "RxJS"-like solution I came up with was to wrap the service method in a second Observable factory method. 我想出的最干净,最“RxJS”的解决方案是将服务方法包装在第二个Observable工厂方法中。

So the following: 所以以下内容:

// service.ts
getData(): Observable<any> {
    return Observable.create((observer: Observer) => {
        this.http.get(url)
          .pipe(catchError(this.handleError)
          .subscribe(res => {
              // Do my service.ts logic.
              // ...
              observer.next(res)
              observer.complete()
          }, err => observer.error(err))
    })
}

// component.ts
ngOnInit() {
    this.service.getData().subscribe(res => {
        // Do my component logic.
        // ...
    }, err => this.errors = err)
}

Use map : 使用map

// service.ts:

import { catchError, map } from 'rxjs/operators';

getData(): Observable<any> {
    return this.http.get(url).pipe(
        map(res => {
            /* Your processing here */
            return res;
        }),
        catchError(this.handleError)
    )
}

Try this way 试试这种方式

service.ts

getData(): Observable<any> {
  return this.http.get(url).map(res=> <any>(res['_body']));
}

component.ts

this.service.getData().subscribe(response=>{
            var res1 = JSON.stringify(response);
            var res2 = JSON.parse(res1);
            var res3 = JSON.parse(res2);
});  //parse response based on your response type 

Option 1 选项1

If you subscribe Observable in component then only component will have that subscription and it must be passed back to service . 如果您在组件中订阅Observable ,则只有组件将具有该订阅,并且必须将其传递回service

Option 2 选项2

Use this pattern. 使用此模式。

service.ts service.ts

    getData(doer: Function) {
        let subscriptions = Observable.of({ data: 'response', isError: false })// request
            .catch(error => Observable.of({ data: error, isError: true })) //handle error
            .do(data => doer(data))
            .subscribe();
        this.handleSubscription(subscriptions); //subscription handling in service
    }

component.ts component.ts

    ngOnInit() {
        this.getData(response => {
            if (response.isError) {
                ///
            } else {
                let data = response.data;
                // Process
            }
        })
    }

You can remove this , and use map . 您可以删除this ,并使用map In subscribe error, you can get error event. 在订阅错误中,您可以获得错误事件。

If you use HttpClient, just use get! 如果您使用HttpClient,只需使用get!

Be careful: All the answers are for <= Angular 4. In Angular 5, you don't need a map() anymore, so just leave that out. 注意:所有的答案都是针对<= Angular 4.在Angular 5中,你不再需要map() ,所以就这样做吧。 just return this.http.get() as it returns an Observable, where you can subscribe on. 只需返回this.http.get()因为它返回一个Observable,您可以在其中订阅。

Furthermore, be aware you have to import HttpClient instead of Http . 此外,请注意您必须导入HttpClient而不是Http

You can directly use "map" and "catch" function on Observable returned by http.get method. 您可以直接在http.get方法返回的Observable上使用“map”和“catch”函数。

import { catchError, map } from 'rxjs/operators';

getData(): Observable<any> {
    return this.http.get(url)
        .map(res => {
            /* Your processing here */
            return res;
        })
        .catch(this.handleError);
}

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

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