DEV Community

Cover image for When a service got destroyed in angular
Bo Vandersteene
Bo Vandersteene

Posted on

When a service got destroyed in angular

Cover Photo by Asa Rodger on Unsplash

If we read the OnDestroy lifecycle hook api description Angular OnDestroy we can use it on services.
But more than this information, we cannot find on it. If we look on the lifecycle hook page. Nothing is explained there, so time to try a few things out.

How we use services?

First we will dig into the usage of services. Services can be provided on different ways to the applications:

On root level

The service is available for everyone, every module can use this root service. It is provided as a singleton, so it lives only ones, and every action on this service, every observable is shared through the whole application.

How can define it on 2 ways. With the providedIn, then you don't provide it in your module



@Injectable({ providedIn: 'root'})
export class RootService { ... }


Enter fullscreen mode Exit fullscreen mode

sidenote on providedIn:

You can also use provideIn: module, but this is still in experimental phase, so be carefull, providedIn: 'root' is good integrated

Or Inject it on the root module



@Injectable()
export class RootService { ... }

@NgModule({
    providers: [ RootService ],
})
export class AppModule{}


Enter fullscreen mode Exit fullscreen mode

On module level

We can also create our services on module level, these services are private and dedicated to that specific module. There logic is shared just inside that module



@Injectable()
export class ModuleService { ... }

@NgModule({
    providers: [ ModuleService ],
})
export class MyCustomModule{}


Enter fullscreen mode Exit fullscreen mode

On component level

These services are injected at component level, so they are only living once the component is alive



// providedIn
@Injectable()
export class Componentervice { ... }

@Component({
    selector: 'my-component',
  template: '...',
    providers: [ Componentervice ],
})
export class MyComponent{}


Enter fullscreen mode Exit fullscreen mode

The lifecycle of a service.

First we are interested when a service is created. We can add a simple test for it. Just create some code like below:



export class MyService {
    constructor(){
        console.log('constructor initialized')
  }
}


Enter fullscreen mode Exit fullscreen mode

To test this logic we have a few testcases, create services on

  • Root level
  • Module level
  • Lazy loaded module
  • Component level

Initialise the service

All service are initialised on the first usage.

A side-note on services. It is not enough to provide it, we should actual perform an action on that service to be initialised, so adding it to a providers array, is not a way of initialising that service. We can have a fist usage of the service on different ways, like use it through a component or a factory, ….

So knowing that, the services are all initialised on the first usage, that is one thing that we are sure about.
That means also, that lazy loaded services are only initialised the first time a route is loaded, an providedIn: ‘root’ service is only initialised the first time it will be used, …. .

Let’s look at the outputs, here we see an interesting pattern. As expected the root, module and lazy service providers are only once created. When we recreate the component, it the service is not created again
Alt Text
Alt Text
Alt Text

But the most interesting part is the component provided service: Each time the component is created, the service is also created
Alt Text

Only component providers are created each time a component is created

Destroy the service

Now we do the same thing but we destroy the service with the ngOnDestroy hook.
For some reasons we thick the preserve log checkbox in google, so we can track the history of our logging even when we leave the page.

Again the testing code will be similar for each service



@Injectable()
export class MyService implements OnDestroy {
  name = 'xxx service';

  constructor(private counterService: CounterService) { 
    console.log('Construct the xxx service')
  }  

  ngOnDestroy() {   
    console.log('Destroy the xxx service')
  }
}


Enter fullscreen mode Exit fullscreen mode

First we look at the component service, as we have the component service each time created, we expect that it destroys when the component get destroys.
Alt Text

If we look at the 3 other services, then we see that these are never destroyed. Even not when we leave the page. You can get it by accident when you leave the page, but you are not ensured about this.
Alt Text

So the conclusion on this ngOnDestroy hook:

Conclusion

  • You are never sure that a service is destroyed, expect if you provide it on component level
  • If you provide a service on component level and you refactor your code, then you need to pay attention on this

Be careful when you use this hook on services

Complete tryout is available on stackblitz:

Top comments (10)

Collapse
 
hp13055 profile image
F.1.armchair.expert • Edited

Your statement that nothing canbe found on the lifecycle hooks page is wrong.
angular.io/guide/lifecycle-hooks#o...
There it is! It says

"OnDestroy()
Put cleanup logic in ngOnDestroy(), the logic that must run before Angular destroys the directive.

This is the time to notify another part of the application that the component is going away.

This is the place to free resources that won't be garbage collected automatically. Unsubscribe from Observables and DOM events. Stop interval timers. Unregister all callbacks that this directive registered with global or application services. You risk memory leaks if you neglect to do so."

Collapse
 
bo profile image
Bo Vandersteene

Yes for a directive the documentation is complete, but what if you're service got destroyed? a service is not the same as a directive IMHO. So please read the article again and don't think about a directive but think about a service.

Collapse
 
hp13055 profile image
F.1.armchair.expert • Edited

@Bo
Your conclusion is wrong.
ngOnDestroy is fired BEFORE the directive gets destroyed. As you can read above, its supposed to be used to clean up resources. Nonetheless the directive may not get destroyed for some reason (for example because a reference is holding up to it). But still : it's working as intended => the event is fired because the component is supposed(!) to fade away.

Collapse
 
bo profile image
Bo Vandersteene

My articles is about services so providers and not directives. So the conclusion is for using ngOnDestroy on a service and NOT on a directive

Thread Thread
 
hp13055 profile image
F.1.armchair.expert • Edited

I've read the article again. You open it with
"If we read the OnDestroy lifecycle hook api description Angular OnDestroy we can use it on services."
But, how do you came to that conclusion? The lifecycle is described for components and directives. Where do you read it could be used on sercices?
You may have misunderstood whats written for onDestroy(). Services are mentioned there, right, but its meant as example to use onDestroy on your component to unregister it from(!) services.

Collapse
 
spiderbomb profile image
spiderbomb

Bo,

Thank you for your article, that was a simple yet elegant experiment.

I actually feel very connected to your conclusions, and these conclusions get more important and helpful when dealing with in service subscriptions.

Collapse
 
metric152 profile image
Ernest

This answered a lot of questions I had about when a service is destroyed. I have a service I want to make sure sticks around because it's a pub/sub. I don't want it to be destroyed so injecting it at the root level solves that problem. The other services I have are tied to a component and they listen to the pub/sub. That service should be destroyed when the page closes.

Collapse
 
akxe profile image
Adam Eisenreich

Services that are bound to module are destroyed when module is destroyed.

But due to unresolved issue modules are never destroyed unless manually done so; That means that its services are never destroyed either! To fix this issue you must first vote on angular issue github.com/angular/angular/issues/...

Collapse
 
dmitryefimenko profile image
Dmitry A. Efimenko

This post needs some serious proofreading. Also, what kind of conclusion is this? Sounds like "I have no clue what's going on. Hopefully someone else will figure it out"

Collapse
 
bo profile image
Bo Vandersteene

If you have some concerns on this article, please share them so I can adjust the article. And about the conclusion. I just want to warn the people that it doesn't work as expected. You are free to use it, but be aware.