AngularJS 之 Factory vs Service vs Provider 已翻译 100%

oschina 投递于 2014/05/05 06:56 (共 15 段, 翻译完成于 05-06)
阅读 50735
收藏 177
24
加载中

当你初试 Angular 时,很自然地就会往 controller 和 scope 里堆满不必要的逻辑。一定要早点意识到,controller 这一层应该很薄;也就是说,应用里大部分的业务逻辑和持久化数据都应该放在 service 里。我每天都会在 Stack Overflow 上看到几个同类的问题,关于如何在 controller 里保存持久化数据。这就不是 controller 该干的事。出于内存性能的考虑,controller 只在需要的时候才会初始化,一旦不需要就会被抛弃。因此,每次当你切换或刷新页面的时候,Angular 会清空当前的 controller。与此同时,service 可以用来永久保存应用的数据,并且这些数据可以在不同的 controller 之间使用。

Angular 提供了3种方法来创建并注册我们自己的 service。

  1. Factory

  2. Service

  3. Provider

戴仓薯
戴仓薯
翻译于 2014/05/05 10:58
8

如果你是“太长的不看”

1) 用 Factory 就是创建一个对象,为它添加属性,然后把这个对象返回出来。你把 service 传进 controller 之后,在 controller 里这个对象里的属性就可以通过 factory 使用了。

FactoryExample1

2) Service 是用"new"关键字实例化的。因此,你应该给"this"添加属性,然后 service 返回"this"。你把 service 传进 controller 之后,在controller里 "this" 上的属性就可以通过 service 来使用了。

ServiceExample2

3) Providers 是唯一一种你可以传进 .config() 函数的 service。当你想要在 service 对象启用之前,先进行模块范围的配置,那就应该用 provider。

ProviderExample3

戴仓薯
戴仓薯
翻译于 2014/05/05 11:09
4

详细解释(对于不是“太长不看”的读者)

为了准确表现出 Factory、Service 和 Provider 之间的差别,下面我们用 3 种不同的方式来构建同一个服务。这个服务会用到 iTunes API 以及使用 $q 的 promise。

1) Factory

Factory 是创建和配置服务最常见的方式。除了“快速浏览”之外,其实没有什么要补充的。只需创建一个对象,为它添加属性,然后返回这个对象就可以了。当你把 factory 传进 controller 中,对象的这些属性就可以通过 factory 访问。更详细的例子如下:

首先创建一个对象,然后返回这个对象,如下。

factory1-4

现在如果我们把"myFactory"传进 controller 里,附加在 "service" 上的任何属性都可以访问到了。

戴仓薯
戴仓薯
翻译于 2014/05/05 11:40
4

现在让我们向回调函数中添加一些“private” 变量。当然 controller中是无法直接访问这些变量的,不过我们最终还是会在“service”中设置setter和个getter 方法,以便必要时修改这些“private”变量。

factory4-5

你可能注意到了,我们没有将变量/函数加到“service”中。我们只是简单的创建他们以便之后的使用和修改。

  •  baseUrl 是iTunes API要求的根URL

  •  _artist 是我们想要查找的艺术家

  • _finalUrl 是最终的权限定URL,即我们调用iTunes的入口

  • makeUrl 是一个创建并返回友好的iTunesURL的函数

既然我们的帮手/私有变量和函数放在的合适的位置,那么让我们向“service”对象中添加一些属性。无论我们向”service“中添加什么, 我们都能在任意一个我们传递进‘myFactory’ 的controller中使用。

麦壳原野
麦壳原野
翻译于 2014/05/06 17:00
3

我们来创建setArtist和getArtist方法来简单的返回或设置artist。同样创建一个方法使用我们创建的URL来调用iTunes API。这个方法将返回一个从iTunes API获取数据后便会满足的promise。如果你对Angular的promise接触不多,我强烈推荐你深入的学习一下它。

  • setArtist 接受一个artist并且允许你设置artist

  • getArtist 返回artist

  • callItunes 首先调用makeUrl()方法以便构建$http请求使用的URL。然后它会设置promise对象,让$http请求我们最终的URL, 再然后呢,因为$http返回一个promise,所以我们可以在请求后调用.success或.error。最后我们可以通过iTunes的数据来解析我们的promise,或者直接‘There was an error’来拒绝它。

factory6

麦壳原野
麦壳原野
翻译于 2014/05/06 17:16
2

现在我们的factory完成了。我们可以将"myFactory"注入到任意controller中了,然后就可以调用我们添加到service对象中的方法了(setArtist,getArtist,和callItunes)。

factory2-7

在上面的controller中,我们注入了‘myFactory’ service对象。然后我们设置$scope 对象的属性。上面唯一棘手的代码是处理promise。因为callItunes返回一个promise对象,一旦我们的promise满足了,我们可以调用.then()方法以及设置$scope.data.artistData。你会注意到我们的controller是非常的“瘦”。因为我们所有的逻辑和持久化数据都存放在了service中而不是controller中。

麦壳原野
麦壳原野
翻译于 2014/05/06 17:29
2

2) Service

当我们创建一个Service时,我们所知道的最重要事可能就是Service通过new关键字实例化对象。这应该可以使熟悉JavaScript的人了解到了这段代码的作用。但对于那些JS背景有限,或者不太熟悉new关键字的作用的人来说可能有点困难。那就让我们来重温一下JavaScript的基本功能,以便帮助我们了解Service究竟做了什么。

让我们先定义一个函数,然后通过new关键字来调用它,看看当解释器遇到了new关键字的时候做了些什么工作,以便帮助我们了解使用new关键字来实例化一个函数时究竟有什么变化。这个的最终结果应该和Service是一样的。

中奖啦
中奖啦
翻译于 2014/05/05 13:01
2

首先,让我们定义一个构造器。

personConstructor-8

这个一个典型的JavaScript式的构造方法。现在,只要我们使用new关键字来调用Person函数,就会将'this'关键字绑定到新创建的对象上。

接下来,让我们给Person的prototype对象添加一个方法,这个方法对所有Person ‘类’的实例都是可用的。

person.prototype-9

现在,由于我们往prototype上添加了一个sayName方法,所以所有的Person实例都可以调用这个方法,并且输出对应实例的name值。

既然我们已经有了一个Person的构造器,并在在其prototype上定义了一个sayName方法,那就让我们去创建一个Person的实例,并调用这个sayName方法。

personInstance-10

接下来,我们把创建Person构造器、往其prototype上添加方法、创建一个Person实例,并调用sayName方法的代码写在一块,如下所示:

PersonCode-11

中奖啦
中奖啦
翻译于 2014/05/05 13:19
1

现在,让我们看一下当我们在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解释器的角度来看整个过程的代码写在了注释里。

PersonCommented-12

中奖啦
中奖啦
翻译于 2014/05/05 13:54
4

现在,既然我们了解了在JavaScript中new关键字是如何工作的,那么在Angular中创建一个Service也应该变得容易理解了。

在创建一个Service时,需要理解的最重要的一件事就是我们使用new关键字去实例化Service对象。结合我们从上面的例子所了解到的知识,你应该已经意识到你可以将一些属性和方法直接添加到this上,之后,在创建Service对象时,this会被作为返回值返回。让我们来看一下这种工作方式。

我们不用像之前Factory中的例子那样创建一个对象,然后返回这个对象。因为我们使用了new关键字来调用,解释器会创建一个对象,并关联它的prototype对象,然后将该对象返回,而不用我们去做这些工作。

中奖啦
中奖啦
翻译于 2014/05/05 19:28
1
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
加载中

评论(34)

l
lioff
一直以为 Factory 是个类 其实是个单例, 并不能在controller 中被修改 ,不知道理解对不对
邪气小生
邪气小生
我觉得说的挺仔细的,挺不错的
发发呆哟
发发呆哟
最后一个provider因为是var thingFormConfig,在return的时候需要thingOnConfig:this.thingFormConfig;
liango
liango
翻译的不错哦
刘凤杰
刘凤杰
还是没看到provide 与service和factory的具体区别,最后使用Provider创建一个service的独特之处是,你可以在Provider对象传递到应用程序的其他部分之前在app.config函数对其进行修改。完全在工作中没用到过
到底tm谁是肖大宝
到底tm谁是肖大宝
不得不赞!谢谢楼主!
巴拉巴拉啦啦
巴拉巴拉啦啦

引用来自“Tu_Minglei”的评论

有一个关键的细节被改变了:
Provider那段的贴图里,原本应该是
···
// Going to set this property on the config function below
this.thingFromConfig = '';
···
在这里变成了
···
// Going to set this property on the config function below
var thingFromConfig = '';
···

这里 this.thingFromConfig = '' 变成 var thingFromConfig = '',差别是挺大的。

然后改了之后就bug了
jQer
jQer

引用来自“jQer”的评论

不会用dom就是不会用,不要说什么复杂, 写dom如果也较复杂,编程就不是地球人可以掌握的了。

引用来自“诸葛囧明”的评论

用榫的看不起用钉的,用钉的看不起用气枪的,一个生产工具有必要用的出自尊心自豪感出来?
你这句话真是P话,你觉得做原子弹的和做包子的技术含量可以相提并论吗? 典型的形而上,思想里一点逻辑意识都没有。
纯洁徐
纯洁徐

引用来自“jQer”的评论

不会用dom就是不会用,不要说什么复杂, 写dom如果也较复杂,编程就不是地球人可以掌握的了。

用榫的看不起用钉的,用钉的看不起用气枪的,一个生产工具有必要用的出自尊心自豪感出来?
纯洁徐
纯洁徐

引用来自“opal”的评论

本来很简单的东西,弄成这么复杂

引用来自“寇德林”的评论

当你写过复杂的webapp,就会知道ng是多么好的东西

引用来自“刘-冬-冬”的评论

我赞同你的意见,如何合理的构建大型web应用,ng是很好的。当然了,Backbone和seajs也不错。

引用来自“耀耀”的评论

angular商业化的飘过
用了ng才晓得原来用jq的每一天都是浑浑噩噩的生活
返回顶部
顶部