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

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

When you first get started with Angular, you’ll naturally find yourself flooding your controllers and scopes with unnecessary logic. It’s important to realize early on that your controller should be very thin; meaning, most of the business logic and persistent data in your application should be taken care of or stored in a service. I see a few questions a day on Stack Overflow regarding someone trying to have persistent data in his or her controller. That’s just not the purpose of a controller. For memory purposes, controllers are instantiated only when they are needed and discarded when they are not. Because of this, every time you switch a route or reload a page, Angular cleans up the current controller. Services however provide a means for keeping data around for the lifetime of an application while they also can be used across different controllers in a consistent manner.

Angular provides us with three ways to create and register our own service.

  1. Factory

  2. Service

  3. Provider

已有 1 人翻译此段
我来翻译

TL;DR

1) When you’re using a Factory you create an object, add properties to it, then return that same object. When you pass this service into your controller, those properties on the object will now be available in that controller through your factory.

FactoryExample1

2) When you’re using Service, it’s instantiated with the ‘new’ keyword. Because of that, you’ll add properties to ‘this’ and the service will return ‘this’. When you pass the service into your controller, those properties on ‘this’ will now be available on that controller through your service.
ServiceExample2

3) Providers are the only service you can pass into your .config() function. Use a provider when you want to provide module-wide configuration for your service object before making it available.

ProviderExample3

已有 1 人翻译此段
我来翻译

NON TL;DR

In order to extensively show the difference between a Factory, Service, and Provider, we’re going to build the same service in three separate ways. The services are going to utilize the iTunes API as well as promises with $q.

1) Factory

Factories are the most popular way to create and configure a service. There’s really not much more than what the TL;DR said. You just create an object, add properties to it, then return that same object. Then when you pass the factory into your controller, those properties on the object will now be available in that controller through your factory. A more extensive example is below.

First we create an object, then return that object like so.
factory1-4

Now whatever properties we attach to ‘service’ will be available to us when we pass ‘myFactory’ into our controller.

已有 1 人翻译此段
我来翻译

Now let’s add some ‘private’ variables to our callback function. These won’t be directly accessible from the controller, but we will eventually set up some getter/setter methods on ‘service’ to be able to alter these ‘private’ variables when needed.

factory4-5

Here you’ll notice we’re not attaching those variables/function to ‘service’. We’re simply creating them in order to either use or modify them later.

      •           baseUrl is the base URL that the iTunes API requires

      •           _artist is the artist we wish to lookup

      •           _finalUrl is the final and fully built URL to which we’ll make the call to iTunes

      •           makeUrl is a function that will create and return our iTunes friendly URL.

Now that our helper/private variables and function are in place, let’s add some properties to the ‘service’ object. Whatever we put on ‘service’ we’ll be able to directly use in whichever controller we pass ‘myFactory’ into.

已有 1 人翻译此段
我来翻译

We are going to create setArtist and getArtist methods that simply return or set the artist. We are also going to create a method that will call the iTunes API with our created URL. This method is going to return a promise that will fulfill once the data has come back from the iTunes API. If you haven’t had much experience using promises in Angular, I highly recommend doing a deep dive on them.

  •           setArtist accepts an artist and allows you to set the artist

  •           getArtist returns the artist

  •           callItunes first calls makeUrl() in order to build the URL we’ll use with our $http request. Then it sets up a promise object, makes an $http request with our final url, then because $http returns a promise, we are able to call .success or .error after our request. We then resolve our promise with the iTunes data, or we reject it with a message saying ‘There was an error’.

factory6

已有 1 人翻译此段
我来翻译

Now our factory is complete. We are now able to inject ‘myFactory’ into any controller and we’ll then be able to call our methods that we attached to our service object (setArtist, getArtist, and callItunes).

factory2-7

In the controller above we’re injecting in the ‘myFactory’ service. We then set properties on our $scope object that are coming from data from ‘myFactory’. The only tricky code above is if you’ve never dealt with promises before. Because callItunes is returning a promise, we are able to use the .then() method and only set $scope.data.artistData once our promise is fulfilled with the iTunes data. You’ll notice our controller is very ‘thin’. All of our logic and persistent data is located in our service, not in our controller.

已有 1 人翻译此段
我来翻译

2) Service

Perhaps the biggest thing to know when dealing with creating a Service is that  that it’s instantiated with the ‘new’ keyword. For you JavaScript gurus this should give you a big hint into the nature of the code. For those of  you with a limited background in JavaScript or for those who aren’t too familiar with what the ‘new’ keyword actually does, let’s review some JavaScript fundamentals that will eventually help us in understanding the nature of a Service.

To really see the changes that occur when you invoke a function with the ‘new’ keyword, let’s create a function and invoke it with the ‘new’ keyword, then let’s show what the interpreter does when it sees the ‘new’ keyword. The end results will both be the same.

已有 1 人翻译此段
我来翻译

First let’s create our Constructor.

personConstructor-8

This is a typical JavaScript constructor function. Now whenever we invoke the Person function using the ‘new’ keyword, ‘this’ will be bound to the newly created object.

Now let’s add a method onto our Person’s prototype so it will be available on every instance of our Person ‘class’.

person.prototype-9

Now, because we put the sayName function on the prototype, every instance of Person will be able to call the sayName function in order alert that instance’s name.

Now that we have our Person constructor function and our sayName function on its prototype, let’s actually create an instance of Person then call the sayName function.

personInstance-10

So all together the code for creating a Person constructor, adding a function to it’s prototype, creating a Person instance, and then calling the function on its prototype looks like this.

PersonCode-11

已有 1 人翻译此段
我来翻译

Now let’s look at what actually is happening when you use the ‘new’ keyword in JavaScript. First thing you should notice is that after using ‘new’ in our example, we’re able to call a method (sayName) on ‘tyler’ just as if it were an object – that’s because it is. So first, we know that our Person constructor is returning an object, whether we can see that in the code or not. Second, we know that because our sayName function is located on the prototype and not directly on the Person instance, the object that the Person function is returning must be delegating to its prototype on failed lookups. In more simple terms, when we call tyler.sayName() the interpreter says “OK, I’m going to look on the ‘tyler’ object we just created, locate the sayName function, then call it. Wait a minute, I don’t see it here – all I see is name and age, let me check the prototype. Yup, looks like it’s on the prototype, let me call it.”.

Below is code for how you can think about what the ‘new’ keyword is actually doing in JavaScript. It’s basically a code example of the above paragraph. I’ve put the ‘interpreter view’ or the way the interpreter sees the code inside of notes.

PersonCommented-12

已有 1 人翻译此段
我来翻译

Now having this knowledge of what the ‘new’ keyword really does in JavaScript, creating a Service in Angular should be easier to understand now.

The biggest thing to understand when creating a Service is knowing that Services are instantiated with the ‘new’ keyword. Combining that knowledge with our examples above, you should now recognize that you’ll be attaching your properties and methods directly to ‘this’ which will then be returned from the Service itself. Let’s take a look at this in action.

Unlike what we originally did with the Factory example, we don’t need to create an object then return that object because, like mentioned many times before, we used the ‘new’ keyword so the interpreter will create that object, have it delegate to it’s prototype, then return it for us without us having to do the work.

已有 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话,你觉得做原子弹的和做包子的技术含量可以相提并论吗? 典型的形而上,思想里一点逻辑意识都没有。
osc_1015876
osc_1015876

引用来自“jQer”的评论

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

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

引用来自“opal”的评论

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

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

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

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

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

引用来自“耀耀”的评论

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