Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
543 views
in Technique[技术] by (71.8m points)

angular - Service is not being singleton for angular2 router lazy loading with loadChildren

Here is the pluker. https://plnkr.co/edit/tsNlmRth4mRzz0svGWLK?p=preview

In which I have created two module with two components and one service each. I want the service should be singleton (save state) in the module level.

If you click on 'Module 1 Page 1' and 'Module 2 Page 2' It will display two different random numbers. As I am generating this number in constructor. So the service is being created each time page change. But module2 is behaving perfectly.

Note: Mode1Module is using loadChildren Mode2Module is using children

I found this same type issue is been fixed earlier as per this angular2 rc5 router service singleton

But I think still it is there. So please help me to solve this out.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Lazy loaded modules have their own root scope. Providers added to lazy loaded modules get an instance in that root scope instead of the root scope of the application. If you add the provider to a module that is not lazy loaded, only a single instance at the application root scope will be created.

https://angular.io/docs/ts/latest/cookbook/ngmodule-faq.html#!#q-lazy-loaded-module-provider-visibility

Why is a service provided in a lazy loaded module visible only to that module?
Unlike providers of the modules loaded at launch, providers of lazy loaded modules are module-scoped.

When the Angular router lazy-loads a module, it creates a new execution context. That context has its own injector which is a direct child of the application injector.

The router adds the lazy module's providers and the providers of its imported modules to this child injector.

These providers are insulated from changes to application providers with the same lookup token. When the router creates a component within the lazy loaded context, Angular prefers service instances created from these providers to the service instances of the application root injector.

https://angular.io/docs/ts/latest/cookbook/ngmodule-faq.html#!#q-why-bad

Why is it bad if SharedModule provides a service to a lazy loaded module?
This question arose in the Angular Module chapter when we discussed the importance of keeping providers out of the SharedModule.

Suppose we had listed the UserService in the module's providers (which we did not). Suppose every module imports this SharedModule (which they all do).

When the app starts, Angular eagerly loads the AppModule and the ContactModule.

Both instances of the imported SharedModule would provide the UserService. Angular registers one of them in the root app injector (see above). Then some component injects UserService, Angular finds it in the app root injector, and delivers the app-wide singleton UserService. No problem.

Now consider the HeroModule which is lazy loaded!

When the router lazy loads the HeroModule, it creates a child injector and registers the UserService provider with that child injector. The child injector is not the root injector.

When Angular creates a lazy HeroComponent, it must inject a UserService. This time it finds a UserService provider in the lazy module's child injector and creates a new instance of the UserService. This is an entirely different UserService instance than the app-wide singleton version that Angular injected in one of the eagerly loaded components.

That's almost certainly a mistake.

Prove it for yourself. Run the live example. Modify the SharedModule so that it provides the UserService rather than the CoreModule. Then toggle between the "Contact" and "Heroes" links a few times. The username goes bonkers as the Angular creates a new UserService instance each time.

https://angular.io/docs/ts/latest/cookbook/ngmodule-faq.html#!#q-why-child-injector

Why does lazy loading create a child injector?
Angular adds @NgModule.providers to the application root injector ... unless the module is lazy loaded. Then it creates a child injector and adds the module's providers to the child injector.

This means that a module behaves differently depending on whether it is loaded during application start or lazy loaded later. Neglecting that difference can lead to adverse consequences.

Why doesn't Angular add lazy loaded providers to the app root injector as it does for eagerly loaded modules? Why the inconsistency?

The answer is grounded in a fundamental characteristic of the Angular dependency injection system. An injector can add providers until it is first used. Once an injector starts creating and delivering services, its provider list is frozen. No new providers allowed.

When an applications starts, Angular first configures the root injector with the providers of all eagerly loaded modules before creating its first component and injecting any of the provided services. Once the application begins, the app root injector is closed to new providers.

Time passes. Application logic triggers lazy loading of a module. Angular must add the lazy loaded module's providers to an injector somewhere. It can't added them to the app root injector because that injector is closed to new providers. So Angular creates a new child injector for the lazy loaded module context.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...