http://www.oschina.net/translate/angularjs-factory-vs-service-vs-provider
http://tylermcginnis.com/angularjs-factory-vs-service-vs-provider/
要注意的文章中,app.provider(...)里的代碼有點出處,之后作者改過,但是轉載的網站上圖片上沒有改掉,應該是
//Going to set this property on the config function belowthis.thingFromConfig = '';
-------------------------------------------------------
當你初試 Angular 時,很自然地就會往 controller 和 scope 里堆滿不必要的邏輯。一定要早點意識到,controller 這一層應該很薄;也就是說,應用里大部分的業務邏輯和持久化數據都應該放在 service 里。我每天都會在 Stack Overflow 上看到幾個同類的問題,關于如何在 controller 里保存持久化數據。這就不是 controller 該干的事。出于內存性能的考慮,controller 只在需要的時候才會初始化,一旦不需要就會被拋棄。因此,每次當你切換或刷新頁面的時候,Angular 會清空當前的 controller。與此同時,service 可以用來永久保存應用的數據,并且這些數據可以在不同的 controller 之間使用。
Angular 提供了3種方法來創建并注冊我們自己的 service。
-
Factory
-
Service
-
Provider
如果你是“太長的不看” 1) 用? Factory 就是創建一個對象,為它添加屬性,然后把這個對象返回出來。你把 service 傳進 controller 之后,在 controller 里這個對象里的屬性就可以通過 factory 使用了。 2) Service? 是用"new"關鍵字實例化的。因此,你應該給"this"添加屬性,然后 service 返回"this"。你把 service 傳進 controller 之后,在controller里 "this" 上的屬性就可以通過 service 來使用了。 3) Providers ?是唯一一種你可以傳進 .config() 函數的 service。當你想要在 service 對象啟用之前,先進行模塊范圍的配置,那就應該用 provider。 |
詳細解釋(對于不是“太長不看”的讀者) 為了準確表現出 Factory、Service 和 Provider 之間的差別,下面我們用 3 種不同的方式來構建同一個服務。這個服務會用到 iTunes API 以及使用 $q 的 promise。 1) Factory Factory 是創建和配置服務最常見的方式。除了“快速瀏覽”之外,其實沒有什么要補充的。只需創建一個對象,為它添加屬性,然后返回這個對象就可以了。當你把 factory 傳進 controller 中,對象的這些屬性就可以通過 factory 訪問。更詳細的例子如下: 首先創建一個對象,然后返回這個對象,如下。 現在如果我們把"myFactory"傳進 controller 里,附加在 "service" 上的任何屬性都可以訪問到了。 |
現在讓我們向回調函數中添加一些“private” 變量。當然 controller中是無法直接訪問這些變量的,不過我們最終還是會在“service”中設置setter和個getter 方法,以便必要時修改這些“private”變量。 你可能注意到了,我們沒有將變量/函數加到“service”中。我們只是簡單的創建他們以便之后的使用和修改。
既然我們的幫手/私有變量和函數放在的合適的位置,那么讓我們向“service”對象中添加一些屬性。無論我們向”service“中添加什么, 我們都能在任意一個我們傳遞進‘myFactory’ 的controller中使用。 |
我們來創建setArtist和getArtist方法來簡單的返回或設置artist。同樣創建一個方法使用我們創 建的URL來調用iTunes API。這個方法將返回一個從iTunes API獲取數據后便會滿足的promise。如果你對Angular的promise接觸不多,我強烈推薦你深入的學習一下它。
|
現在我們的factory完成了。我們可以將"myFactory"注入到任意controller中了,然后就可以調用我們添加到service對象中的方法了(setArtist,getArtist,和callItunes)。 在上面的controller中,我們注入了‘myFactory’ service對象。然后我們設置$scope 對象的屬性。上面唯一棘手的代碼是處理promise。因為callItunes返回一個promise對象,一旦我們的promise滿足了,我們可以 調用.then()方法以及設置$scope.data.artistData。你會注意到我們的controller是非常的“瘦”。因為我們所有的邏 輯和持久化數據都存放在了service中而不是controller中。 |
2) Service 當我們創建一個Service時,我們所知道的最重要事可能就是Service通過new關鍵字實例化對象。這應該可 以使熟悉JavaScript的人了解到了這段代碼的作用。但對于那些JS背景有限,或者不太熟悉new關鍵字的作用的人來說可能有點困難。那就讓我們來 重溫一下JavaScript的基本功能,以便幫助我們了解Service究竟做了什么。 讓我們先定義一個函數,然后通過new關鍵字來調用它,看看當解釋器遇到了new關鍵字的時候做了些什么工作,以便幫助我們了解使用new關鍵字來實例化一個函數時究竟有什么變化。這個的最終結果應該和Service是一樣的。 |
首先,讓我們定義一個構造器。 這個一個典型的JavaScript式的構造方法。現在,只要我們使用new關鍵字來調用Person函數,就會將'this'關鍵字綁定到新創建的對象上。 接下來,讓我們給Person的prototype對象添加一個方法,這個方法對所有Person ‘類’的實例都是可用的。 現在,由于我們往prototype上添加了一個sayName方法,所以所有的Person實例都可以調用這個方法,并且輸出對應實例的name值。 既然我們已經有了一個Person的構造器,并在在其prototype上定義了一個sayName方法,那就讓我們去創建一個Person的實例,并調用這個sayName方法。 接下來,我們把創建Person構造器、往其prototype上添加方法、創建一個Person實例,并調用sayName方法的代碼寫在一塊,如下所示: |
現在,讓我們看一下當我們在JavaScript中使用new關鍵字的時候究竟發生了什么。首先你應該已經注意到的 是,當我們在例子中使用了new關鍵字之后,我們可以通過'tyler'來調用方法(sayName),看上去好像tyler是一個對象——那是因為它確 實成了一個對象。所以,我們知道的第一件事就是我們的Person構造器返回了一個對象(object)。其次,我們知道,由于我們的sayName方法 是定義在Person的prototype上,而不是直接定義在Person的實例上的,所以Person函數返回的對象(tyler)一定是由于未找到 sayName方法,進而去prototype尋找sayName方法的。用更通俗的話來說,當我們調用tyler.sayName()時,JS解釋器 說,“好吧,我先去我們剛創建的'tyler'對象上查找sayName方法,然后調用它。等一下,我沒有在它上面找到sayName方法——我只看到了 name和age,那讓我去prototype找一下吧。沒錯,它在prototype上,那就讓我調用它吧”。 下面的代碼演示了在JavaScript中使用new關鍵之后所做的事。它是上面這一段文字的一個基本的代碼示例。我已經把從JS解釋器的角度來看整個過程的代碼寫在了注釋里。 |
現在,既然我們了解了在JavaScript中new關鍵字是如何工作的,那么在Angular中創建一個Service也應該變得容易理解了。 在創建一個Service時,需要理解的最重要的一件事就是我們使用new關鍵字去實例化Service對象。結合我 們從上面的例子所了解到的知識,你應該已經意識到你可以將一些屬性和方法直接添加到this上,之后,在創建Service對象時,this會被作為返回 值返回。讓我們來看一下這種工作方式。 我們不用像之前Factory中的例子那樣創建一個對象,然后返回這個對象。因為我們使用了new關鍵字來調用,解釋器會創建一個對象,并關聯它的prototype對象,然后將該對象返回,而不用我們去做這些工作。 |
首先,讓我們創建我們的私有輔助函數。它應該看起來和我們在factory中所作的工作很類似。由于我已經在factory的例子中解釋過每一行代碼的含義了,所以我不會在這里多作解釋,如有疑惑,請再次回味一下factory的例子。 接下來,我們將要把可以從控制器中訪問的方法添加到‘this’上。 現在,和使用factory一樣,所有將myService作為參數傳入的控制器都可以訪問到setArtist, getArtist, 和callItunes方法。下面是傳入了myService的控制器(基本上和factory的控制器一樣)。 正如我之前提到的那樣,一旦你了解了new關鍵字的作用,你就會知道在Angular中,Services和Factories幾乎一樣。 |
3) Provider 要記住的關于Provider的最重要的事情是,它們是你可以傳遞到應用程序的app.config部分唯一的服務。 如果你需要在你的服務對象可以在你的應用程序之外任何地方都可用之前改變它的某些部分,這是非常重要的。雖然Services/Factories很相 似,但也有一些差異,我們將會討論它們。 首先,我們用與我們建立Service 和 Factory類似的方式來建立我們的Provider。下面的變量是我們的'私人'和輔助功能。 *同樣地,如果上面的代碼的任何部分令你糾結,請看下 Factory 部分,在那里我更詳細地解釋了這些代碼的作用。 |
必須要注意的一點是只有這些變量和函數是可以在我們的app.config函數中訪問的。這曾一度使我感到困惑,所以 你最好也要知道這點不同之處。你可以把Provider想象成由兩部分組成。第一部分的變量和函數是可以在app.config函數中訪問的,因此你可以 在它們被其他地方訪問到之前來修改它們(如上所示)。第二部分(如下所示)?的變量和函數是可以在任何傳入了’myProvider‘的控制器中進行訪問 的。 當你使用Provider創建一個service時,唯一的可以在你的控制器中訪問的屬性和方法是通過$get()函 數返回內容。下面的代碼將$get方法寫在了’this‘(最終會被函數返回)上。現在,$get函數會返回所有我們希望在控制器中進行訪問的方法和屬 性。下面是代碼示例: |
現在,Provider的完整代碼如下所示: 現在,與我們的Factory和Service類似,setArtist, getArtist, 和callItunes可以在任何一個傳入了 myProvider 的控制器中訪問。下面是myProvider的控制器(幾乎和我們Factory/Service中的控制器一樣)。 正如前面提到的那樣,使用Provider創建一個service的獨特之處是,你可以在Provider對象傳遞到應用程序的其他部分之前在app.config函數對其進行修改。讓我們來看一個對應的例子。 |
現在你可以明白‘thingFromConfig’是怎么樣地在我們的provider中是空字符串,而當它出現在DOM中時,它將是'This sentence was set…’。
謝謝您的閱讀,我希望這有助于你能辨別在Angular中Factory, Service, 和 Provider之間的差異。
*要查看完整的代碼示例,看看運行中的代碼,可以自由地fork我的repo: https://github.com/tylermcginnis33/AngularService