初學 AngularJS 時,看到 service, factory, provider, 常讓人摸不著頭腦。在網路上survey了一陣,StackOver flow 上最被推崇的一篇:Angular.js: service vs provider vs factory?*1 看了之後還是不解其惑。直到最近在閱讀Pawel 的 Mastering Web Application Development with AngularJS*2,裡面有了詳細的說明,讓我瞬間有豁然開朗之感。以下是一些小小的整理。
factory:
provider:
關於 Dependency System
在了解 Service, Factory, Provider的差別前,首先有一個重要的觀念,就是 AngularJS的 Dependency Injection System (DI system)*3。在開發時,有些功能或服務會在不同的 controller 中使用,如果要在每個 controller 裡自己控管該服務,會讓程式重複程式碼變多,也增加了測試時的複雜度,因此 AngularJS 提供了 DI engine 來替 App 控管這些功能和服務。AngularJS DI system 的整理如下:
- 為 AngularJS App 提供了一個抽象層,透過 DI engine 來控管服務的生命週期。
- 所有服務都需要註冊 (Registering Service)。
- 向 DI system 註冊服務有3種「方式」:Service, Factory, Provider。
- 在 DI system 情境下提到 Service,就是一般在說的「服務」,其中包括service,factory,provider 等3種。
- 所有向 DI 註冊的 Service 都是 Singleton !
關於 Registering Service
AngularJS 註冊 Service 的方法有3種:service, factory, provider。我想比較好解釋的方法是先看這三個註冊方式的架構,再來解釋其中的差別。
service:myApp.service('myService', function(){ // 關於這個 service 的code, 當調用 myService 時,會回傳這個 function object 本身! });
factory:
myApp.factory('myFactory', function(){ // 關於這個服務的一些初始化設定,提供了類似 private 的區域。 return { // 當調用 myFactory 時,回傳的物件,可以操作的method, 變數...。只要是合法的 JS object 即可,即便是 function object 也可以。 }; });
provider:
myApp.provider('myProvider', function(){ // 關於這個服務的一些初始化設定,提供了類似 private 的區域。 return { // 在 App 調用 myProvider 前 (angularJS 調用 $get() 方法前),可以在外部對此服務做一些調整 }; $get: function(){ // 此function 等同於 factory 的function,也就是在 controller 裡注入 myProvider 時,所拿到的服務實體 // 如同 factory,可在此對這個服務做一些初始化設定,提供了類似 private 的區域。 return{ // 當拿到此服務實體時,所可以操作的method, 變數... }; }; });
從 AngularJS 所提供的3種 Service 註冊方式來看,複雜度為:service < factory < provider。
詳細說明和整理
service:
透過 service 所註冊的服務,在 controller 取得實體時,拿到的實體就是該傳進去的 function。DI engine 透過所提供的 function 「new」 出該 function 的實體,該 function 相當於是 JS constructor 的功能。DI engine 的服務都是 singleton,也就是 AngularJS 只有在 App 一開始時 會初始化向 DI 註冊的 service,之後調用服務的動作,都只是「取得」服務,不會再有 new 的動作。使用頻率:較少
使用時機:當在外部已經寫好了某個服務的 constructor,可透過 service 直接用該 constructor 向 DI system 註冊服務。
factory:
factory 註冊方式相較 service 註冊方式提供較高的彈性,因為在 function 裡面多了一個 return 區域。在一開始產生該服務實體時,factory 可以有先行的預設值和邏輯運算,而 return 區域則是在 controller 調用該 service 時,拿到的實體物件。因此大部分自製的服務要向 DI 註冊時,透過 factory 註冊比較適合。
使用頻率:較多
使用時機:自行製作該 「App」的服務時。
使用時機:自行製作該 「App」的服務時。
provider:
provider 提供彈性最大的方式讓 user 向 DI system 註冊服務。provider 裡面有兩個結構,一個是 return,另一個是 $get。
return 提供 provider 本身的 function。也就是提供更廣泛的客製化。User 可改變 provider 的設定,但是必須要在 AngularJS 呼叫此服務的 $get function 前。通常是透過可在 App 的 config 做設定。
而 $get function 可以視做和 factory 完全相同的功能,在$get 中的 return 才是 controller 在調用該服務時,取得的實體物件。
使用頻率:普通
使用時機:自行製作該 「App」的服務,且希望該服務能夠客製化,在注入前做一些設定和調整。
最後補充一點,DI system 所提供的服務,可以在 AngularJS app 中任何地方調用,不只限於 controller。
以上,希望能解決一些對 service, factory, provider 的迷惑。
使用頻率:普通
使用時機:自行製作該 「App」的服務,且希望該服務能夠客製化,在注入前做一些設定和調整。
最後補充一點,DI system 所提供的服務,可以在 AngularJS app 中任何地方調用,不只限於 controller。
以上,希望能解決一些對 service, factory, provider 的迷惑。
最近剛好自己在看相關就點近來看哈哈~那個... Factory 那邊的原始碼有 typo,應該是 myApp.factory
回覆刪除喔喔!Thanks a lot!
刪除您寫得真清楚,非常感謝您的分享!!
回覆刪除謝謝您的鼓勵!
刪除