简体   繁体   English

每次通过注入组件实例化角服务

[英]Angular service instantiated every time by injection to component

I implemented a service which should fetch data once and cache the result. 我实现了一项服务,该服务应一次获取数据并缓存结果。 The service is at root level. 该服务位于根级别。 Every time I inject this service in a constructor of a component and subscribe to the method the service make a new http request. 每当我将此服务注入组件的构造函数中并订阅该方法时,该服务都会发出新的http请求。

I already tried to put the request code out of the constructor to the method. 我已经尝试过将请求代码从构造函数中移到方法中。

@Injectable({
  providedIn: 'root'
})
export class SessionService {
  private api = Configuration.api + 'session/';
  private readonly session$: Observable<Session>;

  constructor(private http: HttpClient) {
    this.session$ = this.http
      .get<any>(`${this.api}current`, {withCredentials: true})
      .pipe(
        timeout(Configuration.timeout),
        retry(Configuration.retry),
        map(data => {
            return data.session as Session;
          }
        ),
        catchError(ErrorService.handleError)
      );
  }

  getCurrentSession(): Observable<Session> {
    return this.session$;
  }
}

export class Component implements OnInit, AfterContentInit {
session = Session.empty();

  constructor(
    private _s: SessionService) {
    this._s.getCurrentSession().subscribe(session => this.session = session);
  }
}

The aim is to do a request once and cache the result in a variable. 目的是执行一次请求并将结果缓存在变量中。

observables are definitions of a stream, they execute on every subscription, so everytime you're just subscribing to the http request which causes it to execute. 可观察对象是流的定义,它们在每个订阅上执行,因此每次您只订阅导致其执行的http请求时。 to get around this, you need to subscribe in your constructor and store the result in a subject that will handle the caching: 为了解决这个问题,您需要订阅构造函数并将结果存储在将处理缓存的主题中:

export class SessionService {
  private api = Configuration.api + 'session/';

  private session$ = new ReplaySubject<Session>(1);

  constructor(private http: HttpClient) {
    this.loadSession();
  }

  loadSession() {
    this.http
      .get<any>(`${this.api}current`, {withCredentials: true})
      .pipe(
        timeout(Configuration.timeout),
        retry(Configuration.retry),
        map(data => {
            return data.session as Session;
          }
        ),
        catchError(ErrorService.handleError)
      ).subscribe(this.session$);
  }

  getCurrentSession(): Observable<Session> {
    return this.session$.asObservable();
  }
}

though you could also get away with doing this: 尽管您也可以这样做:

this.session$ = this.http
  .get<any>(`${this.api}current`, {withCredentials: true})
  .pipe(
    timeout(Configuration.timeout),
    retry(Configuration.retry),
    map(data => {
        return data.session as Session;
      }
    ),
    catchError(ErrorService.handleError),
    shareReplay(1)
  );

the shareReplay operator more or less does exactly the same thing. shareReplay运算符或多或少执行完全相同的操作。 The reason I prefer the original method I suggested is because it gives an easier way to force the data to reload if needed. 我之所以喜欢我建议的原始方法,是因为它提供了一种更简便的方法,可以在需要时强制重新加载数据。

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

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