前言,學習完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出來看看:
可以看到,黑色部分圈起來的是基本的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的q服務。q服務是在AngularJS中用來創建promise對象的,但它首先創建一個defered對象:
var defered = $q.defer();
- 1
- 1
打印該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來執行回調。