【问题标题】:Angular service instantiated every time by injection to component每次通过注入组件来实例化 Angular 服务
【发布时间】:2019-08-10 16:08:11
【问题描述】:

我实现了一个服务,它应该获取一次数据并缓存结果。该服务处于根级别。每次我在组件的构造函数中注入此服务并订阅该服务的方法时都会发出一个新的 http 请求。

我已经尝试将请求代码从构造函数中放到方法中。

@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);
  }
}

目的是执行一次请求并将结果缓存在变量中。

【问题讨论】:

    标签: angular rxjs angular8


    【解决方案1】:

    observables 是流的定义,它们在每次订阅时执行,因此每次您只是订阅导致它执行的 http 请求。为了解决这个问题,您需要在构造函数中订阅并将结果存储在将处理缓存的主题中:

    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();
      }
    }
    

    虽然你也可以这样做:

    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)
      );
    

    shareReplay 操作符或多或少做同样的事情。我更喜欢我建议的原始方法的原因是因为它提供了一种更简单的方法来强制数据在需要时重新加载。

    【讨论】:

    • getCurrentSession 返回 Observable&lt;{}&gt; 而不是 Observable&lt;Session&gt;
    猜你喜欢
    • 1970-01-01
    • 2020-12-21
    • 2017-04-16
    • 2016-04-21
    • 1970-01-01
    • 1970-01-01
    • 2021-02-04
    • 2016-08-08
    • 2021-02-04
    相关资源
    最近更新 更多