2016-12-05 27 views
12

这里是pluker。 https://plnkr.co/edit/tsNlmRth4mRzz0svGWLK?p=preview服务是不是单身的angular2路由器延迟加载loadChildren

其中我创建了两个模块,每个模块包含两个组件和一个服务。 我希望服务在模块级别应该是singleton(保存状态)。

如果您点击“模块1页1”和“模块2页2”,它将显示两个不同的随机数。正如我在构造函数中产生这个数字。因此,每次页面更改时都会创建该服务。但是module2表现完美。

注: Mode1Module使用loadChildren Mode2Module使用children

我发现这个同类型的问题早已经按本angular2 rc5 router service singleton

固定的,但我认为它仍然是存在的。所以请帮我解决这个问题。

+0

工作吗?你的抢劫者有什么问题?我在第1页和第2页看到了同样的信息,我认为这是正确的行为,不是吗?你有另外一个问题吗? – vinagreti

+0

如果您检查模块1的页面1,页面2.它不同。但对于模块2是一样的。 Where模块的页面1和页面2将相同。 –

+0

你说得对,问题仍然存在,我们可以在你的闯入者身上看到它。我已经在本地进行了测试,使用角度cli和缺陷持久性。您可以在此问题中发布消息https://github.com/angular/angular/issues/11125包含您的plunker链接,以便他们可以查看错误。参考这个SO问题并说我们已经用system.js和angular-cli进行了测试。谢谢! – vinagreti

回答

16

延迟加载的模块具有其自己的根作用域。添加到延迟加载模块的提供程序将在该根作用域中获取实例,而不是应用程序的根作用域。 如果您将提供程序添加到未加载的模块,则只会创建应用程序根作用域中的单个实例。

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

为什么延迟加载的模块仅可见于 模块中提供的服务?
与启动时加载模块的提供者不同,延迟加载模块的提供者是模块范围的。

当Angular路由器延迟加载模块时,它会创建一个新的执行上下文 。该环境具有其自己的注射器,该注射器是应用注射器的直接子模块 。

路由器将懒惰模块的提供商和其导入模块的提供商 添加到此子注入器。

这些提供程序与使用相同查找令牌的应用程序提供商 的更改无关。当路由器在延迟加载的上下文中创建组件 时,Angular更愿意从这些提供程序创建 到应用程序根 注入器的服务实例的服务实例。

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

为什么是坏,如果SharedModule提供服务,以懒加载 模块?
这个问题出现在Angular Module章节中,我们 讨论了保持提供者不在SharedModule中的重要性。

假设我们在模块的提供者中列出了UserService(我们没有这个 )。假设每个模块都导入了这个SharedModule(它们全都是这样做的)。

当应用程序启动时,Angular急切地加载AppModule和 ContactModule。

导入的SharedModule的两个实例都会提供 UserService。 Angular在根应用程序注入器 (参见上文)中注册其中的一个。然后一些组件注入UserService,Angular在应用程序根注入器中发现它 ,并提供应用程序范围的单身人员 UserService。没问题。

现在考虑一下懒加载的HeroModule!

当路由器懒惰加载HeroModule时,它会创建一个子注入器 并向该子注入器注册UserService提供程序。儿童注射器不是根注射器。

当Angular创建一个懒惰的HeroComponent时,它必须注入一个 UserService。这一次,它在惰性 模块的子注入器中找到一个UserService提供程序,并创建一个UserService的新实例。 这是一个完全不同的UserService实例,它与应用程序范围内的单一版本的Angular注入到一个热切加载的组件中。

这几乎肯定是一个错误。

证明你自己。运行现场示例。修改SharedModule ,以便它提供UserService而不是CoreModule。然后 在“联系人”和“英雄”链接之间切换几次。由于Angular每次都会创建一个新的UserService 实例,因此 用户名变为焦点。

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

为什么懒加载创建一个子注入?
Angular将 @ NgModule.providers添加到应用程序根注入器中......除非 模块被延迟加载。然后它创建一个子注入器并将 模块的提供程序添加到子注入器。

这意味着模块的行为有所不同,具体取决于它是在应用程序启动期间加载还是稍后加载延迟。忽视 这种差异会导致不良后果。

为什么Angular不会像加载模块一样为应用程序根注入器 添加延迟加载的提供程序?为什么不一致?

答案基于角度依赖注入系统的基本特性。注射器可以添加供应商,直到它首次使用为 。一旦注入器开始创建和交付服务,其供应商列表将被冻结。没有新的提供者允许。

当应用程序启动时,第一角构成根 喷射器与所有急切装载的模块的提供者 创建其第一组分和注入任何所提供 服务之前。一旦应用程序开始,应用程序根注入器将关闭 给新的提供者。

时间流逝。应用程序逻辑触发延迟加载模块。 Angular必须将惰性加载模块的提供程序添加到某处的注入器 。它不能将它们添加到应用程序根注入器,因为该注入器已关闭到新的提供程序。所以Angular为延迟加载的模块上下文创建了一个新的子进程注入器 。

+0

那么如何在延迟加载的模块组件之间共享状态数据呢? –

+1

延迟加载的模块也会注入全局服务。只需在非延迟加载模块中提供服务即可。只是相反的方式不起作用。延迟加载模块的服务仅适用于本模块和其他模块中的组件和服务,但不适用于非延迟加载或其他laty-loaded模块 –

+0

,这意味着如果我们在app.module.ts中导入服务比它将可用于所有惰性加载或非惰性加载模块? @GünterZöchbauer –

11

正如@GünterZöchbauer所述,这是对Angular文档的解释,其中延迟加载的模块获取它们自己的服务实例。如果服务是为了成为一个真正的单,那么应该

直接提供入AppModule

@NgModule({ 
    providers: [ SingletonService ] 
}) 
class AppModule {} 

这些服务是应用程序范围内,甚至懒加载模块。因此,您无需将其添加到那些惰性加载模块的providers

导入提供服务到AppModule

。注意,惯例是使用forRoot,如[该文档]提到的模块[1]

@NgModule({ 
}) 
class CoreModule { 
    forRoot() { 
    return { 
     ngModule: SomeModule, 
     providers: [SingletonService] 
    } 
    } 
} 

@NgModule({ 
    imports: [ CoreModule.forRoot() ] 
}) 
class AppModule {} 

forRoot应只能在AppModule的导入中调用。这将确保只有AppModule添加提供者。任何延迟加载的模块都可以访问由AppModule提供的相同单例服务。

+0

我的服务应该是单身,但不应用于应用程序。而是通过它定义的模块。我只想将其归档。假设我正在用不同的模块创建一个松散耦合的应用程序。每个模块与其他模块是独立的。在将所有模块集成到我的应用程序时,我不想将所有单例服务都放到我的AppModule中。 –

+0

查看最后一个示例,如果在延迟加载的模块中声明了coremodule,该怎么办?如果我做coremodule,那么我必须导入它,所以它不懒惰......换句话说 - 我可以使用forroot来装载懒惰的模块吗? –

0

您可以通过在一个MOD1组件包裹Mod1Page1和Mod1Page2成分为孩子解决这个问题:

@Component({ 
    template: '<router-outlet></router-outlet>' 
}) 
class Mod1Component {} 

const routes: Routes = [ 
    { 
    path: '', 
    component:Mod1Component, 
    children:[ 
     { 
     path : 'page1', 
     component : Mod1Page1Component 
     }, 
     { 
     path : 'page2', 
     component : Mod1Page2Component 
     } 
    ] 
    } 
]; 

const routedComponents = [Mod1Component,Mod1Page1Component, Mod1Page2Component]; 

Plnkr link to solved fork

Mod1Service将被创建,当你从组件导航到任何Mod1Module的组件,每次任何其他模块,但是当您浏览beetwen时,Mod1Module的组件服务将不会被重新创建。

相关问题