Reputation: 6244
I'm writing an Angular 7 application. I'm wondering if there is a way to print the reference of an active object (in my case it's a service https://angular.io/guide/architecture-services).
I need this to understand if there are many instances of that object in memory because I'm having some trouble and debugging is not helping me to find the problem. My guess it's I've more instances of the same class in memory. Unfortunately just printing:
console.log(myService)
it doesn't print any in memory reference of the object, so I can't understand if what I'm seeing it's the same object or a new one.
Is there a way to get it as I get when from Chrome I acquire a memory snapshot?
Upvotes: 0
Views: 438
Reputation: 54771
it doesn't print any in memory reference of the object, so I can't understand if what I'm seeing it's the same object or a new one.
Angular does not duplicate services, but it duplicates modules and that results in duplicate providers.
This most commonly occurs with lazy loaded modules, and I'll demonstrate below.
@NgModule({...}
export class SharedModule {
provides: [MyService]
}
@NgModule({...}
export class AppModule {
imports: [SharedModule]
}
@NgModule({...}
export class LazyModule {
imports: [SharedModule]
}
In the above modules the SharedModule
is used by both AppModule
and LazyModule
, but LazyModule
is loaded by the router via lazy loading.
The problem here is that a new instance of SharedModule
is created specifically for LazyModule
. It will not use the same reference used by AppModule
, and since ShareModule
has providers those will be new providers.
You can try adding a guard to your service to prevent duplicate instances.
@Injector()
export class MyService {
public constructor(@Optional() @SkipSelf() duplicate: MyService) {
if(duplicate) {
throw new Error('Service can not be duplicated');
}
}
}
Angular has since added a feature provideIn
which allows you to add a service to the root module, and prevents it from being provided more than once. You can just update the injector for this.
@Injector({provideIn: 'root'})
For most cases this works fine.
I need this to understand if there are many instances of that object in memory because I'm having some trouble and debugging is not helping me to find the problem.
You mentioned in the comments that this would be easy in Java to debug, but in JavaScript it's a little more abstract.
var x = new MyService();
var y = {...x};
var z = Object.assign({}, x);
Looking at the code above. How many instances are there of MyService
?
From a JavaScript perspective there are 3, because x !== y && x !== z && y !== z
but from a Java perspective there is only 1 instance. That's because the constructor was only used once.
In Angular, a service declared with @Injector({...})
will always have it's constructor called for each provider in the dependency injector. So if you want to track the number of instances it's best to log that information from the constructor.
Kind of a long answer, but that's my take on it.
Upvotes: 1
Reputation: 340
I think services in angular must be single tones so there is just one object of each service in memory.
Upvotes: 0
Reputation: 128
providedIn annotation is available since angular 6.
If don't include you service in any specific module, angular compiler decide if the service is used on the application and initialize the first used time.
@Injectable({
providedIn: 'root',
})
Upvotes: 0