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