angularJS $q $http 與promise對象的關係

前言,學習完ES6的promise對象,對於angularJS $q 和$http 有些許疑問。

一、介紹:

$http服務是AngularJS系統自帶的,可以用來進行網絡通信、獲取遠程服務器的數據。要記住的是,$http是對瀏覽器XMLHttpRequest的封裝,也就是說,它其實是Ajax。


二、$http的基本用法:

使用的時候寫好幾個參數:

  • options:包括url、method(get或post)
  • successFn:成功的回調
  • errorFn:失敗的回調

格式:

$http(options).success(successFn).error(errorFn)
  • 1
  • 1

例子:(html文件就是一個按鈕和顯示結果的文本框,在這裏就不寫出來了)

angular.module('myDemo', [])

    .controller('myController', ['$scope', '$http', function ($scope, $http) {
        $scope.testHttp = function () {
            $http({
                method: 'GET',
                url: 'https://randomuser.me/api/'
            }).success(function (data) {    // 這裏的data的類型是object,並且,它已經是返回數據的“數據”部分(如暫時不理解,後面會說到)
                console.log(angular.toJson(data, true));
                $scope.result = data;
            }).error(function (err) {
                console.log(err);
            })
        }
    }]);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

這裏,$http(options)返回的是一個被封裝的promise對象,我們可以console.log出來看看: 
$http返回的promise對象 
可以看到,黑色部分圈起來的是基本的promise部分(擁有then,catch,finally函數),除了這些函數以外,這個promise對象還有success和error函數(見紅色橫線),這是$http返回的時候封裝的,供我們使用的時候更方便。比如上述例子中,註釋裏說,success的回調函數返回的data直接就是我們想要的“數據部分”,那麼如果我用的是then,那麼返回的除了數據部分,還有額外的部分(比如狀態碼),這時候我就得自己拿出這個“數據部分”,代碼如下:

var promise = ...;  // 省略$http過程

promise.then(function (data) {
        // realData被包含在data的“data”字段中,一般它纔是我們想要的
        var realData = data.data;
        console.log(realData);
    }, function (err) {

    });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

三、$q的介紹與用處:

在上述例子中,我們是在Controller層寫了網絡請求。但是我們知道,在angularjs的MVC框架之中,業務邏輯(包括網絡請求)的部分應該儘可能寫到Service層中,而讓Controller的邏輯儘可能少。但是,怎麼把網絡請求最終得到的有用的數據,返回給controller呢?這裏有兩種思路:

  • 方法一:把$http(options)返回的promise對象直接在Service中返回。在controller中拿到之後,再寫success和error的回調。
  • 方法二:在Service中返回一個自定義的promise對象,用來回調給controller。這裏的回調者,由$q創建的“defered”對象來擔任。

方法一寫起來比較簡單,在這裏就不演示了。 
在演示方法二之前,先簡單介紹一下AngularJS的qq服務是在AngularJS中用來創建promise對象的,但它首先創建一個defered對象:

var defered = $q.defer();
  • 1
  • 1

打印該defered對象: 
defered對象屬性一覽 
可以看到它有3個方法:resolve,reject,notify,分別對應於接受、拒絕、通知,具體用法在這裏就不說了。還有一個promise屬性,它的值就是一個基本的promise對象,主要用來返回。比如上面的例子,我可以這樣寫:

services.js

...
    .factory('userService', ['$http', '$q', function ($http, $q) {

        var userService = {};   // 返回的服務

        this.urlForRandomUser = "https://randomuser.me/api/";

        var that = this; // 獲取當前作用域,下面要用到
        userService.getRandomUser = function () {

            var defered = $q.defer();

            $http.get(that.urlForRandomUser)
                .success(function (data) {
                    defered.resolve(data.results[0]);
                })
                .error(function (err) {
                    defered.reject(err);
                });
            return defered.promise; // 把defered對象中的promise對象返回出來
        };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

controllers.js

...
    .controller('firstController', ['$scope', 'userService', function ($scope, user) {

        $scope.getUser = function () {

            function success(data) {
                var str = angular.toJson(data, true);   // 用angular的格式化json的方法,更爲清晰
                $scope.result = str;
            }

            function error(err) {
                $scope.result = err;
                alert('error occured!\n' + err);
            }

            // 注意這裏不能用success或error函數,用then就好
            user.getRandomUser().then(success, error);
        }

    }])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

要注意的是最後那裏,defered的promise是基本的promise對象,並沒有success和error函數,所以要用then來執行回調。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章