Angular7 + RxJs同一Observable的多个订阅者

问题描述 投票:0回答:4

这可能是一个菜鸟问题,但我可以找到它的参考。

我有两个组件放在不同的地方,每个组件使用一个服务来查询端点并获取一些数据(例如用户配置文件)。

该服务返回一个observable,我需要observable是唯一的或者至少要发出一个唯一的请求。

// Service, shared across multiple components
@Injectable()
export class SomeService {
    getData(): Observable<DataModel> {
        return this._http.get<DataResponse>('/some-route').pipe(
          map((response: DataResponse) => this.handleResponse(response)),
          share() // is this right ?
        );
    }

}

// Component requesting data
@Component({ selector: '...', ... })
export class FirstComponent implements OnInit {
  constructor(private _service: SomeService) { }

    ngOnInit() {
        this._service.getData().subscribe(
          data => {
            console.log(data);
          }
        );
      }
}

// Another component requesting the same data
@Component({ selector: '...', ... })
export class SecondComponent implements OnInit {
  constructor(private _service: SomeService) { }

    ngOnInit() {
        this._service.getData().subscribe(
          data => {
            console.log(data);
          }
        );
      }
}

该服务工作,它获取数据,但请求发送两次,我只想要发送一个请求。组件同时存在(假设一个在顶部,第二个在屏幕的底部)。所以他们同时提出请求。

有没有办法服务只发送一个请求。

而BTW,第一个请求的状态为200,第二个请求的状态为304。

谢谢。

UPDATE

可能解决方案

到目前为止,我通过添加Service变量来管理

private _observable: Observable<DataModel>;

然后在获取数据时

getData(): Observable<DataModel> {
    if (!this._observable) {
        this._observable = this._http.get<DataResponse>('/some-route').pipe(
          map((response: DataResponse) => this.handleResponse(response)),
          // HERE IS THE TRICK
          publishLast(),
          refCount()
        )
    }

    return this_observable;
}

诀窍是使用publishLast和refCount

有更好的方式/想法吗?

angular rxjs angular7 rxjs6
4个回答
1
投票

看看我的库ngx-rxcache。它简化了国家的管理。

https://github.com/adriandavidbrand/ngx-rxcache

@Injectable()
export class SomeService {
 private dataCache = this.cache.get<DataModel>({
    id: 'some uniquie id',
    load: true,
    construct: () => this.http.get<DataResponse>('/some-route').pipe(
      map((response: DataResponse) => this.handleResponse(response))
    )
 });

 data$ = this.dataCache.value$;

 constructor(cache: RxCacheService, http: HttpClient) {}
}

然后,您可以访问服务上的数据

this.service.data$;

https://medium.com/@adrianbrand/angular-state-management-with-rxcache-468a865fc3fb


0
投票

您可以轻松地将请求分组到一个Observable中,该Observable将在使用forkJoin Operator完成所有请求时解析

这是一个例子

  public requestDataFromMultipleSources(): Observable<any[]> {
    let response1 = this.http.get(requestUrl1);
    let response2 = this.http.get(requestUrl2);
    let response3 = this.http.get(requestUrl3);
    // Observable.forkJoin (RxJS 5) changes to just forkJoin() in RxJS 6
    return forkJoin([response1, response2, response3]);
  }

在您的示例中,您应该在父组件中发出请求。然后将结果注入子组件


0
投票

你可以使用shareReplay,它会将来自source observable的事件重播给所有订阅者并确保你只共享最后一个结果

 shareReplay(1)

所以你的代码看起来像这样

getData(): Observable<DataModel> {
    return this._http.get<DataResponse>('/some-route').pipe(
      map((response: DataResponse) => this.handleResponse(response)),
      shareReplay(1) 
    );
}

0
投票

我发现以下模式对此有效:

@Injectable()
export class SomeService {
  myDataObservable$: Observable<DataModel>;

  constructor( ) {
    this.myDataObservable$ = this.getData().pipe(shareReplay());
  }

  getData(): Observable<DataModel> {
    return this._http.get<DataResponse>('/some-route').pipe(
      map((response: DataResponse) => this.handleResponse(response))
    );
  }
}
  1. 在包含将由多个组件使用的observable的服务上执行属性(myDataObservable $)。
  2. 有一个执行http请求的方法(getData())。
  3. 在构造函数中,调用方法并添加shareReplay()。
  4. 在组件中,您使用“this.someService.myDataObservable $ .subscribe(...)”

使用此模式,在至少一个组件中调用myDataObservable $上的subscribe之前,不会发送http请求。在第一个组件调用subscribe之后,所有后续订阅都将使用已存在的值,因此您将不会有多个http请求。

© www.soinside.com 2019 - 2024. All rights reserved.