Angular 服务不是全局单例
Angular Service not a global singleton
我的印象是 Angular Service
是 Singleton
,但最近发现,或者至少看起来,该服务只是组件实例的单例,并且组件的 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
我的印象是 Angular Service
是 Singleton
,但最近发现,或者至少看起来,该服务只是组件实例的单例,并且组件的 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