2016-12-05 26 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的組件服務將不會被重新創建。

相關問題