服務是AngularJS中很是重要的一個概念,雖然咱們有了控制器,但考慮到其生命實在脆弱,咱們須要用到服務。git
起初用service
時,我便把service
和factory()
理所固然地關聯起來了。
確實,factory()
是建立一個服務的最簡單的方式,但服務並不是僅此而已。github
這裏記錄一下我對服務的一些簡單認識。
api
很是重要的一點 —— 服務是單例。
一個服務在一個AngularJS應用中只會被$injector
實例化一次,並貫穿應用的整個生命週期,與脆弱的控制器們進行通訊。ide
先從註冊一個服務開始,註冊服務的最多見方式即是factory()
。
好比:函數
var myApp = angular.module('myApp',[]) .factory('myService',function() { return {}; });
factory()
以對象或者函數形式返回一個服務。
咱們試試給myService注入$http
服務,寫一個像那麼回事的東西。this
(ps:找了一些URL都不是很理想,我也只好學別人的demo,從github獲取用戶的活動日誌信息)url
注入? 把服務注入給控制器也是這樣,把服務的名字放到參數列表裏就算是注入了,但這只是簡單的方式。日誌
好了,先把myService修改一下:code
.factory('myService',function($http) { return { getUserActivities: function(username){ return $http({ method: 'JSONP', url:'https://api.github.com/users/'+username+'/events?callback=JSON_CALLBACK' }); } }; })
根據輸入的用戶名進行請求,輸出活動信息,視圖以下:對象
<div ng-controller="myController"> <input type="text" ng-model="username" /> <table border="1"> <tr> <th></th> <th>user</th> <th>to</th> <th>at</th> </tr> <tr ng-repeat="activity in activities"> <td><img src="{{activity.actor.avatar_url}}" width="25px" height="25px"/></td> <td>{{ activity.actor.login }} </td> <td>{{ activity.repo.name }}</td> <td>{{activity.created_at}}</td> </tr> </table> </div>
咱們須要$watch
這個變量,但須要注意的是,若是請求頻率超過限制,github會給個403。
所以還須要用$timeout
控制一下請求頻率,一段時間以內重複請求就把以前的幹掉。
控制器調用服務代碼以下:
.controller('myController',function($scope,myService,$timeout,$log){ var timeout; $scope.$watch('username',function(){ if(timeout){ $timeout.cancel(timeout) $log.info('timeout:::'+timeout); } timeout= $timeout(function(){ myService.getUserActivities($scope.username) .success(function(response, status, headers, config){ $scope.activities = response.data; }) .error(function(response, status, headers, config){ $log.info(status) })},1000); }); })
用factory()
註冊一個服務彷佛不那麼複雜。
事實上,咱們有5種方式來建立服務:
最簡單的方式,該函數接收2個參數
多是由於更加語義化的緣故,比起factory()
,我更喜歡service()
。
service也一樣接收2個參數,分別是:
試着改用service()
:
.service('myService',function($http) { this.getUserActivities = function(username){ return $http({ method: 'JSONP', url:'https://api.github.com/users/'+username+'/events?callback=JSON_CALLBACK' }); } })
這兩個名字感受比較另類,它們的參數都是同樣的:
僅從語義上來說,若是服務的$get
方法只是返回個常量,這兩個方法確實適合。
可能會嘗試寫個函數進去,若是隻是定義的話則不會報錯。
但不會有相應的provider,調用時也會提示該服務不是一個函數之類的問題。
因此仍是老老實實地這樣使用:
.constant('serviceId','00001')
那二者的區別又是什麼?
區別在於注入到config()
時,以上面的serviceId
爲例。
若是serviceId是個constant
,咱們能夠將serviceId注入到config()中,可是沒法將serviceIdProvider
注入到config()中,而value
則恰好相反。
provider()
是最原始的方法。
咱們試着用factory()
和provider()
建立相同的服務進行對比。
.factory('aService',{ 'name':'a' }) .provider('bService',{ $get: {'name':'b'} })
也就是說factory()
的第二個參數至關因而$get
?
provider()
接收兩個參數:
$provide
服務在運行時初始化provider,$injector
調用$get
建立服務實例。
那爲何要用provider()
而不是其餘方式? 關鍵在於config()
,若是咱們給多個應用共享某個服務,但在注入服務以前給注入到不一樣應用的服務進行相應的設置,則須要在config()中經過服務的provider進行設置,好比加個decorator
什麼的。
就是裝飾服務,添加功能或者徹底改變服務。
decorator()
接收兩個參數
$injector
調用該函數。下面是一個例子,在得到用戶活動信息後輸出耗時:
.config(function(myServiceProvider,$provide){ $provide.decorator('myService',function($delegate,$log) { var activities = function(username) { var startedAt = new Date(); var activities = $delegate.getUserActivities(username); activities.finally(function() { $log.info("Fetching activities" +" took " +(new Date() - startedAt) + "ms"); }); return activities; }; return {getUserActivities:activities}; }); })