引言angular2相比1引入了更完善的模塊系統,回憶ng1的應用中通常在頁面的html標簽或body標簽中添加ng-app節點,值為應用的模塊名,整個應用都將圍繞這個模塊來展開,到了ng2,模塊概念完善了很多,並且再不是由一個模塊來統治整個應用(當然非要這麼做也可以),本文就將敘述一番ng2中的模 ...
引言
angular2相比1引入了更完善的模塊系統,回憶ng1的應用中通常在頁面的html標簽或body標簽中添加ng-app節點,值為應用的模塊名,整個應用都將圍繞這個模塊來展開,到了ng2,模塊概念完善了很多,並且再不是由一個模塊來統治整個應用(當然非要這麼做也可以),本文就將敘述一番ng2中的模塊體系,以及如何統籌ng2模塊最終組合成一個完整的應用。
一、根模塊、子模塊與惰性載入
先說根模塊。一個ng2應用至少要有一個根模塊,包含ng2自帶的BrowserModule,並聲明為引導模塊,在應用啟動時將從此模塊展開。
隨著應用的擴大,所有的事情都在一個模塊中完成難免會變亂(某種程度上看ng1應用就是這麼做的,並且細分了控制器來拆分應用,這其實浪費了最頂層模塊的意義),所以自然而然能想到,可以將系統分為多個模塊,每個模塊都只做各自的事情而互不幹擾,所以進一步的思路就是,用來根模塊來引導程式並管理所有子模塊(通過路由定向以及為它們提供全局配置與服務實例),所有的具體業務就交給各個子模塊來完成。
然後會有一個問題,那就是既然系統已經被這麼多個子模塊瓜分了,並且這些子模塊也不可能同時全部都會被使用,也就是只有其被激活時才有用,那仍然在應用引導時從根模塊載入所有子模塊必然會導致性能的浪費以及拖慢執行速度。此時惰性載入模塊就派上用場了,將一個子模塊定義為惰性載入後,只有在通過路由激活此模塊時才會開始載入此模塊(並且ng2甚至支持非同步預載入,即後臺預載入懶載入的模塊,這樣當懶載入模塊需要被載入時其實其已經載入完成了,又加快了響應速度)。
二、除了模塊之外
每個模塊都有自己的事情要做,通常包括:
- 引入其他模塊 這個在第三部分細說
- 聲明模塊包含的組件、指令與管道 所有的組件、指令或管道都必須依附於某個模塊,並只在此模塊中可用。
- 定義模塊提供的服務 服務也有自己所屬的模塊,但由於服務是全局單例的,所以只要在一個模塊中提供之後,全局都通用。註:若多個模塊同時提供了服務(通常發生在模塊間混亂的import時),一般情況下ng2能識別並只保留一個實例,但在惰性載入的模塊中則會發生不可預計的錯誤,所以一定要避免。
- 定義模塊將導出的組件、指令與管道(還可以是此模塊引入的模塊) 與(1配合使用,同樣在第三部分細說。
三、模塊的關聯
模塊之間一定要有共用或繼承資源的方式,不然的話每個子模塊都必須實現可能用到的全部功能。
比如一個消息彈窗組件,不可能每個子模塊都自己聲明一個消息組件然後使用,這樣的維護壓力很大且代碼嚴重浪費。
此時就用到了模塊的引入和導出——
模塊A可以引入另一個模塊B,然後A就可以使用B中導出的組件、管道和指令。
當我們要使用系統指令(如ngIf、ngFor等)時,也必須引入系統模塊,有一個巧妙的辦法就是實現上圖這樣的共用模塊,在引入系統模塊並導出的同時再導出自定義的其他指令、組件或管道。然後所有引入了此共用模塊的子模塊就能使用這些系統指令和共用指令了。
有一個基礎的問題是服務需不需要導出,答案是否定的。服務不需要導出,因為服務是全局單例的,一旦被初始化,就已經全局通用了,相反如果重覆的導入提供了同一服務的模塊就可能發生問題:
B提供服務B_S,A導入了B,C也導入了B。這種情況下ng2會找到兩處B_S的提供,但ng2尚能夠將其保持在一個實例B_S。但若模塊C為惰性載入的模塊,在C被創建時,其實會重新初始化一個實例B_S,從C跳轉回到A時,又會創建一個B_S,來回每次跳轉都是如此,結局就會變得混亂不堪。
對於服務更好的做法是寫一個核心模塊,專門提供全局服務,保證此模塊只會被根模塊引用一次,然後所有的子模塊就都已經可以使用這些全局服務了。
四、ng2模塊體系
最後給出一套ng2項目構建的體系,這也是總結歸納了ng2官網的推薦得出的ng2項目的模塊體系。
總體思路就是:
> 1.根模塊負責全局的路由。
> 2.核心模塊負責全局服務,也可以定義一些只在根模塊中使用的組件等,並只能由根模塊引入一次,不再導出。
> 3.共用模塊不做服務的提供,而是定義全局共用的組件等,以及幫助子模塊導入系統模塊,讓子模塊只需要導入此共用模塊就夠了。
> 4.子模塊內部可以細分自己的子路由到具體的子組件,以及提供自己的服務等。
> 5.除了頁面入口模塊(即除了根模塊外的具體業務模塊)之外的其他子模塊均考慮寫成惰性載入的模塊,以提升頁面引導的速度減少性能浪費。
> 6.當需要一個比較通用的全局服務時,可以將其加入CoreModule,也可以再創建一個僅被根模塊引入的特性模塊。進一步的,甚至可以將此模塊發佈到npm,這就需要更強的編碼能力和技術積累了。