Angular 服务不是全局单例

Angular Service not a global singleton

我的印象是 Angular ServiceSingleton,但最近发现,或者至少看起来,该服务只是组件实例的单例,并且组件的 children.

考虑以下代码:

const CACHE_REFRESH_INTERVAL = 1800000; //30 minutes
const CACHE_SIZE = 1;

const COMPANY_CACHE_KEY = 'company_cache_key';

@Injectable({
  providedIn: "root"
})
export class CompanyService {

  private companyCache: Map<string, Observable<any>> = new Map();

  constructor(private httpClient: HttpClient) { }

  public getAllCompanies(): Observable<CompanyViewModel[]> {
    if (!this.companyCache[COMPANY_CACHE_KEY]) {
      const timer$ = timer(0, CACHE_REFRESH_INTERVAL);
      this.companyCache[COMPANY_CACHE_KEY] = timer$.pipe(
        switchMap(_ => this.getAllCompaniesHttpRequest()),
        shareReplay(CACHE_SIZE),
        refCount(),
        catchError(err => this.companyCache[COMPANY_CACHE_KEY] = undefined) //prevents storing error in cache
      );
    }
    return this.companyCache[COMPANY_CACHE_KEY];
  }

  private getAllCompaniesHttpRequest(): Observable<CompanyViewModel[]> {
    return this.httpClient.get<CompanyViewModel[]>(environment.endpoints.company.getAllCompanies());
  }
}

比方说,ComponentA 通过组件的指导程序注入此服务。当ComponentA调用CompanyService.getAllCompanies()方法时,结果会存储在companyCache中。现在用户导航到一个新的 URL,ComponentA 被销毁,以及服务的实例。导航回 ComponentA,注入一个新的服务实例,companyCache 再次为空。

我的假设正确吗?我可以在整个应用程序中将服务设置为单例吗?

服务在应用级别是单例。

以这个简单的 stackblitz demo

我有一个从构造函数中设置随机数的简单服务。

@Injectable({
  providedIn: 'root'
})
export class Service {
  constructor() {
    this.rnd = Math.random();
  }

  private rnd: number;

  getRand(): number {
    return this.rnd;
  }
}

我有一个这样的组件结构,服务被注入到 2 个 "child" 组件中(不是实际的子组件,但这是我设置的导航模式):

|- home

|- component a
|--  inject service

|- component b
|--  inject service

从home导航到组件a时,会显示服务构造函数中设置的随机数。

当我导航回到主页(查看控制台以查看组件 a 已被销毁),然后导航到组件 b 时,它会显示在服务的构造函数中设置的随机数。

在应用程序的生命周期内,随机数保持不变。对我来说,这证明即使服务不是 "in scope",它仍然在内存中。

更不用说 the docs 在第一行谈论这个:

A singleton service is a service for which only one instance exists in an app.

I was under the impression that a Angular Service is a Singleton, but have recently discovered, or atleast it seems, that the service is only a singleton to the instance of the component and the component's children.

当您将 CompanyService 放入组件的 providers 数组中时,就会发生这种情况。默认情况下,服务是单例的,但您可以覆盖它。

接个小服务:

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class SomeService {
  public someRandomValue = Math.random();

  constructor() {
    console.log("I've just got instantiated.");
  }
}

和两个在其提供程序数组中具有 SomeService 的组件。对于他们两个,someRandomValue 将不同,并且 "I've just got instantiated." 将被记录两次:

https://stackblitz.com/edit/angular-oua1nf?file=src%2Fapp%2Fsome.service.ts