你可能知道,當咱們經過@NgModule()
裝飾器來聲明一個service
時,它將符合單例模式,同時還意味着它與整個應用的生命週期保持一致。好比:git
export class AdminService { data = Array(10000).fill(dummy); } @NgModule({ providers: [AdminService, AdminDataService] })
咱們在剛開始接觸Angular的時候,老是不計後果的將全部service
都使用@NgModule()
來聲明,這將會形成一個不易發現的問題:github
You are not releasing memory.
在上面的例子中,儘管你再也不須要這些內存中儲存的數據,可是讓咱們停下來仔細想想,咱們真的須要將一個service
聲明爲單例的嗎?緩存
好比,在咱們整個應用中,咱們會有一個管理區域須要呈現大量的表格數據(同時這些數據只在這個管理區域展示),這些數據會儲存在內存中。在這種狀況下,咱們沒有必要將這個service
聲明爲單例的,由於咱們不須要緩衝層來緩存這些數據以供應用中的其餘模塊使用。ide
進一步講,當前咱們僅僅是想使這些表格數據在多個component
之間共享,同時將數據與service
中的多個helper
方法耦合起來。因此咱們徹底能夠直接使用@Component()
裝飾器來聲明service
,這樣它就會成爲一個非單例的service
,以下:函數
@Component({ selector: 'admin-tab', providers: [AdminService, AdminDataService] })
這樣作的好處是,當Angular註銷組件實例時,Angular將同時註銷與之綁定的service
實例,y也會釋放那些用來儲存數據的內存。工具
許多開發者也許不知道非單例的service
有ngOnDestroy()
生命週期,因此你也能夠在這個生命週期中進行一些銷燬邏輯代碼的編寫,好比:ui
export class AdminService implements OnDestroy { ngOnDestroy() { // Clean subscriptions, intervals, etc } }
另外,若是咱們調用NgModuleRef.destroy()
或者PlatformRef.destroy()
,單例service
的ngOnDestroy
鉤子函數也會被[執行]。(https://github.com/angular/an...。翻譯
之因此翻譯了這篇文章,是由於今天在整理項目代碼的時候,偶然發現了這個問題,雖然我使用Angular
也有一段時間了,可是依然將不少沒有必要聲明在NgModule
中的服務以單例模式的方式聲明瞭。文章中指出的問題確實是一個重要但又難以發現的問題。3d
大致總結一下Angular
中聲明service
的不一樣方式和應用場景。code
@Component
這時service
與組件自己生命週期保持一致,非單例,適合聲明一些須要暫存數據的工具類或者僅在某個或某幾個組件中須要緩存數據的狀態管理類service
@NgModule
的providers
這時service
與應用自己生命週期保持一致(非懶加載),單例,適合聲明一些須要在全局緩存數據的狀態管理類service
。
可是有一個特例,懶加載模塊中的service
是會在模塊加載時從新建立一個實例的,懶加載模塊中均會注入後建立的service
實例,所以懶加載模塊與非懶加載模塊間的service
非單例。
forRoot
使用forRoot
能夠保證當前模塊即便是懶加載模塊,在加載時也不會從新建立一個新的service
實例,由於懶加載模塊在加載時,會臨時建立一個從屬於根injector
的子injector
,根據Angular中的依賴注入流程,當嘗試經過一個子injector
中注入不存在的實例對象時,會嘗試向父級injector
獲取,所以最終可保證該service
在應用任何地方被注入均是單例。
關於官方文檔的介紹,能夠參考Providers和Singleton Services。