使用Angular 2中的Observables获取数据一次

Dav*_*vid 10 javascript observable rxjs angular

我有一个服务,很多我的Angular 2组件使用过多次.它从Web API获取客户数据并返回Observable:

getCustomers() {
   return this.http
        .get(this.baseURI + this.url)
        .map((r: Response) => {
            let a = r.json() as Customer[];                       
            return a;                         
        });               
}    
Run Code Online (Sandbox Code Playgroud)

我在我的根组件中注入了这个服务,在每个想要访问客户的组件中,我只订阅了Observable:

this.customerService.getCustomers().subscribe(v => this.items = v);
Run Code Online (Sandbox Code Playgroud)

但是,订阅我的Observable的每个组件都会导致另一个HTTP请求的执行.但是只获取一次数据就足够了.如果我尝试share(),它不能解决我的问题:

getCustomers() {
   return this.http
        .get(this.baseURI + this.url)
        .map((r: Response) => {
            let a = r.json() as Customer[];                       
            return a;                         
        }).share();               
}   
Run Code Online (Sandbox Code Playgroud)

仍然是同一个问题.操作员必须使用的任何建议只能获取一次数据?

Dan*_*cal 13

1)您只需将下载的数据保存在您的服务中:

export class CustomersService {
  protected _customers: Array<Customer>;

  constructor(public http: Http) {}

  public getCustomers(): Observable<Array<Customer>> {
    return new Observable(observer => {
      if (this._customers) {
        observer.next(this._customers);
        return observer.complete();
      }
      this.http
        .get(this.baseURI + this.url)
        .map((r: Response) => (r.json() as Array<Customer>))
        .subscribe((customers: Array<Customer>) => {
          this._customers = customers;
          observer.next(this.customers);
          observer.complete();
        });
    });
  }
}
Run Code Online (Sandbox Code Playgroud)

2)更短的接近refresh参数:

export class CustomersService {
  protected _customers: Array<Customer>;

  constructor(public http: Http) {}

  public getCustomers(refresh?: boolean): Observable<Array<Customer>> {
    if (!refresh && this._customers) {
      return Observable.of(this._customers);
    }
    return this.http
            .get(this.baseURI + this.url)
            .map((c: Response) => (c.json() as Array<Customer>))
            .do((customers: Array<Customer>) => {
                this._customers = customers;
            });
    });
  }
}
Run Code Online (Sandbox Code Playgroud)

3)利用ReplaySubject:

export class CustomersService {
  protected _customers$: ReplaySubject<Array<Customer>> = new ReplaySubject(1);
  protected _customersInitialized: boolean;

  constructor(public http: Http) {}

  public getCustomers(refresh?: boolean): Observable<Array<Customer>> {
    if (refresh || !this._customersInitialized) {
      this._customersInitialized = true;
      this.http
        .get(this.baseURI + this.url)
        .map((c: Response) => (c.json() as Array<Customer>))
        .subscribe((customers: Array<Customer>) => {
          this._customers$.next(customers);
        });
    }
    return this._customers$.asObservable().skip(+refresh).distinctUntilChanged();
  }
}
Run Code Online (Sandbox Code Playgroud)

然后:

this.customersService.getCustomers()
    .subscribe(customers => this.customers = customers);
Run Code Online (Sandbox Code Playgroud)

您还可以通过以下方式公开始终最新的customers字段,SomeService以便进行读取(例如在模板中显示):

public get customers(): ReadonlyArray<Customer> {
  return this._customers;
}
Run Code Online (Sandbox Code Playgroud)