promise 是一種用異步方式處理值的方法,promise是對象,代表了一個函數最終可能的返回值或拋出的異常。在與遠程對象打交道非常有用,可以把它們看成一個遠程對象的代理。

要在Angular中創建promise需要使用內置的$q服務。先用factory定義一個服務,注入$q服務。
angular.module('readApp').factory('asyncService', [
"$q", function ($q) {
var myAsync=function(flag) {
var deferred = $q.defer();
if (flag) {
deferred.resolve("well done!");
} else {
deferred.reject("lost!");
}
return deferred.promise;
}
return {
myAsync: myAsync
};
}
]);
獲得deferred的方法和jquery不同,但resolve和reject是一樣的,最后返回的是promise屬性,而不是promise方法。再看如何調用:
angular.module('readApp').controller('testCtrl', ["$scope", "asyncService", function ($scope, asyncService) {
$scope.flag = true;
$scope.handle = function () {
asyncService.myAsync($scope.flag).then(function (result) {
$scope.status = result;
return result;
}, function (error) {
$scope.status = error;
return error;
});
}
}])
獲取到服務后,調用then方法。then有三個參數,分別對應成功回調、失敗回調和通知回調。這個和jquery是一致的
<div class="container">
<label for="flag">成功
<input type="checkbox" id="flag" ng-model="flag" name="name" /> <br />
<div>{{status}}</div>
<button ng-click="handle()">點擊</button>
</label>
</div>
<footer-n
結果:

不同的是,Angular的promise沒有公布jquery那么多方法,我們可以看一下deferred.promise這個屬性,它是一個$$state對象。根據Promise/A規范,一個Promise只要具備一個then方法即可。

注意到,Angular中的deferred有notify、reject、resolve三個主要方法和一個promise屬性,而這個promise的原型連中包含了我們調用的then方法,then方法在執行完之后會派生一個新的promise,因此可以鏈式調用。沒有done和fail,但是還提供了catch和finally方法。catch就相當於是error方法了。而finally方法就像強類型語言中的場景一樣,當我們需要釋放一個資源,或者是運行一些清理工作,不管promise是成功還是失敗時,這個方法會很有用。要注意的是finally是ie中的一個保留字,需要下面這樣調用:
promise['finally'](function() {});
除了defer()方法,$q還有all和when方法,all(promises)可以將多個promise合並成一個,但如果任意一個promise拒絕了,那么結果的promise也會拒絕。而when(value)方法把一個可能是值或者promise包裝成一個$q promise。有了jQuery中的when,這兩個方法不難理解。關於這三個方法的示例可以參考這篇博客:AngularJS 中的Promise --- $q服務詳解
Angular的$q的靈感是來自[Kris Kowal's Q],從官方的注釋中可以看到
* This is an implementation of promises/deferred objects inspired by * [Kris Kowal's Q](https://github.com/kriskowal/q). * $q can be used in two fashions --- one which is more similar to Kris Kowal's Q or jQuery's Deferred * implementations, and the other which resembles ES6 promises to some degree.
支持兩種風格,可以像Q庫或者jQuery的deferred一樣,也可以用ES6語法,文檔給出了示例,也是就構造函數法來定義:
var asyncGreet = function (name) {
return $q(function (resolve, reject) {
console.log(resolve, reject);
setTimeout(function () {
if (name=="stone") {
resolve('Hello, ' + name + '!');
} else {
reject('Greeting ' + name + ' is not allowed.');
}
}, 1000);
});
};
通知(notify/progress)回調還不支持這種寫法。對比看,沒太大差別。
function asyncGreet(name) {
var deferred = $q.defer();
setTimeout(function() {
deferred.notify('About to greet ' + name + '.');
if (okToGreet(name)) {
deferred.resolve('Hello, ' + name + '!');
} else {
deferred.reject('Greeting ' + name + ' is not allowed.');
}
}, 1000);
return deferred.promise;
}
大致看下源碼如何實現:
Promise:
function Promise() {
this.$$state = { status: 0 };
}
extend(Promise.prototype, {
then: function(onFulfilled, onRejected, progressBack) {
if (isUndefined(onFulfilled) && isUndefined(onRejected) && isUndefined(progressBack)) {
return this;
}
var result = new Deferred();
this.$$state.pending = this.$$state.pending || [];
this.$$state.pending.push([result, onFulfilled, onRejected, progressBack]);
if (this.$$state.status > 0) scheduleProcessQueue(this.$$state);
return result.promise;
},
"catch": function(callback) {
return this.then(null, callback);
},
"finally": function(callback, progressBack) {
return this.then(function(value) {
return handleCallback(value, true, callback);
}, function(error) {
return handleCallback(error, false, callback);
}, progressBack);
}
});
創建了一個Promise對象包含一個$$state屬性,然后擴展了then,catch,finally方法(注意后兩個帶了引號)。then的三個參數都是回調函數,對應成功、失敗、通知回調,並在then方法中創建了一個deferred作為結果,將回調函數和創建的deferred都存入了數組,主意到這是一個二維數組,每個then對應的promise和回調函數都在這個數組里面。最后返回promise。而catch和finally內部也是調用的then。只要狀態大於0也就promise獲得了結果就用scheduleProcessQueue處理回調。 Deferred 內部包含了一個promise以及resolve、reject和notify三個方法。jQuery.deferred 中處理的是三個回調隊列,Angular中處理的一個是二維數組。
$http的是一個promise對象:
var promise = $q.when(config);
//some code
promise = promise.then(thenFn, rejectFn);
}
if (useLegacyPromise) {
promise.success = function(fn) {
assertArgFn(fn, 'fn');
promise.then(function(response) {
fn(response.data, response.status, response.headers, config);
});
return promise;
};
promise.error = function(fn) {
assertArgFn(fn, 'fn');
promise.then(null, function(response) {
fn(response.data, response.status, response.headers, config);
});
return promise;
};
} else {
promise.success = $httpMinErrLegacyFn('success');
promise.error = $httpMinErrLegacyFn('error');
}
return promise;
用then擴展了error和succes方法,因此我們可以這樣使用:
booksData.getbookById(bookid).success(function(data) {
vm.book = data;
}).error(function (e) {
console.log(e);
vm.message = "Sorry, something's gone wrong ";
});
$Interval也是一個promise對象。
AngularJS 中的Promise --- $q服務詳解
http://www.cnblogs.com/xing901022/p/4928147.html
