AngularJS入門之Services


關於AngularJS中的DI

在開始說AngularJS的Service之前,我們先來簡單講講DI(Dependency Injection,通常中文稱之為“依賴注入”)。

DI是一種軟件設計模式,主要為了解決組件獲取它的依賴組件的問題。DI的概念滲透在AngularJS的各個地方,AngularJS使用一個專門的子系統($injector)進行DI管理,這個過程包括了創建組件、解析、獲取它的依賴組件,並將這些依賴組件回傳給請求組件。

 

我們其實已經在不知不覺中使用DI了(比如在AngularJS自定義Directive中的出現過):

app.directive('myCurrentTime', ['$interval', 'dateFilter', function ($interval, dateFilter) {
}

 

上述代碼片段在添加Controller時,其中$interval就是Controller中依賴注入Service的推薦方法。由於$injector的存在,對於我們只需將所需服務的名稱傳入我們的模塊即可,底層的工作都將由$injector包辦。

$injector的原理如下圖:

 

AngularJS中使用DI添加Service的三種方法: 

方式1(內聯注解,推薦使用):

app.controller('myController', ['$scope', 'dateFilter', function ($scope, dateFilter) { }]);

 

方式2($inject注解):

1 var MyController = function($scope, dateFilter) {
2   // ...
3 }
4 MyController.$inject = ['$scope', 'dateFilter'];
5 someModule.controller('MyController', MyController);

 

方式3(隱式注解,不推薦使用):

app.controller('myController', function ($scope, dateFilter) { });

 

推薦使用方式1的理由是:

  • 寫法上比方法2更簡單明了
  • 比方法3更可靠(由於Javascript可以被壓縮,AngularJS又是通過解析服務名稱找到對應Service的,因此Javascript壓縮之后AngularJS將無法找到指定的Service,但字符串不會被壓縮,因此單獨以字符串指定Service的名稱可以避免這個問題)

 

使用方式1或方式2的注意點:

由於上述第二點原因,AngularJS在編譯Html時,由$injector將數組中Service的名稱與方法體中的Service進行一一映射。這種映射關系必須遵守由AngularJS的約定:

  • 數組中Service名稱的個數必須與方法體中Service名稱的個數一致
  • 數組中Service的順序必須與方法體中Serivce的順序一致

 

如果為了編碼規范需要強制使用顯式DI(也就是方式1或者方式2),可使用ng-strict-di屬性,這樣AngularJS在遇到隱式DI(也就是方式3)時將會報錯。

示例1:

 1 <!DOCTYPE >
 2 <html>
 3 <head>
 4     <script src="/Scripts/angular.js"></script>
 5     <script type="text/javascript">
 6         (function () {
 7             var app = angular.module('diTest', []);
 8 
 9             app.controller('myController1', ['$scope', function ($scope) {
10             }]);
11 
12             // 方式1 隱式DI,在指定了ng-strict-di后,將會報錯
13             //app.controller('myController1', function ($scope) {
14             //});
15 
16 
17 
18             var myController2 = function ($scope) {
19             };
20             myController2.$inject = ['$scope'];
21             app.controller('myController2', myController2);
22 
23             // 方式2 隱式DI,在指定了ng-strict-di后,將會報錯
24             //var myController2 = function ($scope) {
25             //};
26             //app.controller('myController2', myController2);
27         })();
28     </script>
29 </head>
30 <body ng-app="diTest" ng-strict-di>
31     <div ng-controller="myController1 as myCtrl1">
32     </div>
33 
34     <div ng-controller="myController2 as myCtrl2">
35     </div>
36 </body>
37 </html>

 

示例1中,因為body使用了ng-strict-di屬性,因此當使用方式1或者方式2的隱式DI時,AngularJS將會拋出如下錯誤:

 

 AngularJS中的Services:

AngularJS提供了很多Services,常用的如$http,是集成在AngularJS和核心庫中的,另外有一部分如$animate是獨立的模塊。由於篇幅問題,我們先以$http為例了解一下AngularJS的Service。

迄今為止我所有的AngularJS系列的文章中,所有的數據均是通過ng-init或者在$scope中初始化數組來完成的。但實際項目中,我們的數據都會從服務器獲取。寫個例子來演示一下這個過程。

 

Step 1,創建一個名為data.txt的文件,里面包含一個Json對象:

{
    "students": [
        {
            "Name": "Jack", 
            "Age": 21
        }, 
        {
            "Name": "Alice", 
            "Age": 20
        }, 
        {
            "Name": "Tom", 
            "Age": 21
        }, 
        {
            "Name": "Sophie", 
            "Age": 19
        }
    ]
}

 

Step 2,使用$http的get方法獲取data.txt的數據,並將數據賦值給$scope.students:

app.controller('myController', ['$scope', '$http', function ($scope, $http) {
    $scope.students = [];
    $http.get('data.txt').
        success(function (data, status, headers, config) {
            $scope.students = data.students;
            console.log(data);
           console.log(data.students);
             console.log($scope.students);
         }).
         error(function (data, status, headers, config) {
         });
 }]);

 

Step 3,使用ng-repeat顯示students的信息:

<div ng-repeat="stu in students">
    <p>Name: {{stu.Name}}</p>
    <p>Age: {{stu.Age}}</p>
    <br />
</div>

 

完整的Html代碼如下:

 1 <!DOCTYPE >
 2 <html>
 3 <head>
 4     <script src="/Scripts/angular.js"></script>
 5     <script type="text/javascript">
 6         (function () {
 7             var app = angular.module('httpServiceTest', []);
 8 
 9             app.controller('myController', ['$scope', '$http', function ($scope, $http) {
10                 $scope.students = [];
11                 $http.get('data.txt').
12                   success(function (data, status, headers, config) {
13                       $scope.students = data.students;
14                       console.log(data);
15                       console.log(data.students);
16                       console.log($scope.students);
17                   }).
18                   error(function (data, status, headers, config) {
19                   });
20             }]);
21         })();
22     </script>
23 </head>
24 <body ng-app="httpServiceTest" ng-controller="myController">
25     <div ng-repeat="stu in students">
26         <p>Name: {{stu.Name}}</p>
27         <p>Age: {{stu.Age}}</p>
28         <br />
29     </div>
30 </body>
31 </html>
View Code

 

關於$http:

$http的基本調用格式:

$http(config).success(function(data,status,headers,config){ }).error(function(data,status,headers,config){ });

 

config為Json對象,完整參數說明如下:

  • method{string} - HTTP方法,示例值GET、POST等
  • url{string} - 請求資源的絕對或者相對路徑,示例值 http://mytest.com/user/example 或 /myservice/user/example
  • params{Object.<string|Object>} - URL的請求參數部分,可以直接是一個完整的字符串也可以是一個對象,對象將被自動JSon序列化(一般給Get使用)
  • data{string|Object} - 請求參數內容(一般給Post使用)
  • headers{Object} - Http請求的Headers
  • xsrfHeaderName{string} - 防XSRF(跨站請求偽造)的Header名稱
  • xsrfCookieName{string} - 防XSRF的Cookie名稱
  • transformRequest{function(data,headersGetter)|Array.<function(data,headersGetter)>} - 自定義Http請求格式的方法
  • transformResponse{function(data, headersGetter, status)|Array.<function(data, headersGetter, status)>} - 自定義Http響應格式的方法
  • paramSerializer{string|function(Object):string} - 序列化params的方法
  • cache{boolean|Cache} - boolean類型指定是否緩存GET請求,或者指定一個由$cacheFactory創建的緩存實例
  • timeout{number|Promise} - number為請求超時時間(單位為毫秒);或者指定一個可以中斷請求的promise
  • withCredentials{boolean} - 是否需要證書,詳見:requests with credentials
  • responseType{string} - 返回類型,詳見:requestType

 

 注意:由於是入門類文章,本章中對於以上各個參數的用法不深入展開了,這部分內容今后單獨開一章來討論。

 

$http調用原型中,方法success和error為$http調用返回的promise,promise是由AngularJS的核心服務$q提供的一種處理異步請求的實現方式,關於promise的細節,本篇也不做展開,可參考官方文檔:https://docs.angularjs.org/api/ng/service/$q。我們只需知道,由於success和error是$http方法調用返回的promise(承諾),因此在異步完成$http方法的調用完成、失敗或超時后,最終必定會調用success或者error方法。

 

$http的調用原型看起來比較復雜,為了便於使用,AngularJS提供了$http調用的快捷方式(如$http.get, $http.post等),其基本格式如下:

$http.get('/someUrl').success(successCallback);
$http.post('/someUrl', data).success(successCallback);

 

$http所有方法的快捷方式(其中[config]表示config為可選參數):

 

好了,通過本篇的介紹,我們已經基本了解了DI的概念,以及AngularJS中如何使用DI來完成Service的使用,我們還重點看了一下$http以及它的使用方式,當然,關於更多$http的細節今后會單獨開一篇討論的。

 

如果你和我一樣也是AngularJS的新手,那通過這么多天的學習后,我們已經能使用AngularJS完成一個真正的Web網站的原型的搭建了:AngularJS負責前端,數據由后端服務提供。還猶豫什么呢,趕緊自己試試吧。

 

參考資料

AngularJS官方文檔DI:https://docs.angularjs.org/guide/di

AngularJS官方文檔Service:https://docs.angularjs.org/api/ng/service

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM