Angular JS中的promise
如何创建一个promise
想要在Angular中创建promise,可以使用内置的$q服务。$q服务在它的deferred API中提供了一些方法。
首先,需要把$q服务注入到想要使用它的对象中。
angular.module('myApp', [])
.factory('GithubService', ['$q', function($q) {
// 现在就可以访问到$q库了
}]);
要创建一个deferred对象,可以调用defer()方法:
var deferred = $q.defer();
deferred对象暴露了三个方法,以及一个可以用于处理promise的promise属性。
resolve(value)
resolve函数用这个值来执行deferred promise。
deferred.resolve({name: "Ari", username: "@auser"});
reject(reason)
这个方法用一个原因来拒绝deferred promise。它等同于使用一个“拒绝”来执行一个promise。
deferred.reject("Can't update user");
// 等同于
deferred.resolve($q.reject("Can't update user"));
notify(value)
这个方法用promise的执行状态来进行响应。
例如,如果我们要从promise返回一个状态,可以使用notify()函数来传送它。
假设我们想要从一个promise创建多个长时间运行的请求。可以调用notify函数发回一个过 程通知:
.factory('GithubService', function ($q, $http) { // 从仓库获取事件
var getEventsFromRepo = function () { // 任务
}
var service = {
makeMultipleRequests: function (repos) {
var d = $q.defer(),
percentComplete = 0,
output = [];
for (var i = 0; i < repos.length; i++) {
output.push(getEventsFromRepo(repos[i]));
percentComplete = (i + 1) / repos.length * 100;
d.notify(percentComplete);
}
d.resolve(output);
return d.promise;
14
}
}
return service;
});
then(successFn, errorFn, notifyFn)
无论promise成功还是失败了,当结果可用之后,then都会立刻异步调用successFn或者errorFn。这个方法始终用一个参数来调用回调函数:结果,或者是拒绝的理由。
在promise被执行或者拒绝之前,notifyFn回调可能会被调用零到多次,以提供过程状态的提示。
then()方法总是返回一个新的promise,可以通过successFn或者errFn这样的返回值执行或者被拒绝。它也能通过notifyFn提供通知。
catch(errorFn)
这个方法就只是个帮助函数,能让我们用.catch(function(reason){})取代error回调:
$http.get('/repos/angular/angular.js/pulls')
.catch(function(reason) {
deferred.reject(reason);
});
finally(callback)
finally方法允许我们观察promise的履行或者拒绝,而无需修改结果的值。当我们需要释放 一个资源,或者是运行一些清理工作,不管promise是成功还是失败时,这个方法会很有用。
我们不能直接调用这个方法,因为finally是IE中JavaScript的一个保留字。纠结到最后,只 好这样调用它了:
promise['finally'](function() {});
Angular的$q deferred对象是可以串成链的,这样即使是then,返回的也是一个promise。这个promise一被执行,then返回的promise就已经是resolved或者rejected的了。
promise链式请求
then方法在初始promise被执行之后,返回一个新的派生promise。这种返回形式给了我们一 种特有的能力,把另一个then接在初始的then方法结果之后。
// 一个响应promise的服务
GithubService.then(function (data) {
var events = [];
for(var i=0;i<data.length;i++){
events.push(data[i].events);
}
return events;
}).then(function(events){
$scope.events = events;
});
在本例中,我们可以创建一个执行链,它允许我们中断基于更多功能的应用流程,可以籍此 导向不同的结果。这个中断能让我们在执行链的任意时刻暂停或者推迟promise的执行。
$q库自带了几个不同的有用方法。
all(promises)
如果我们有多个promise,想要把它们合并成一个,可以使用$q.all(promises)方法来把它 们合并成一个promise。这个方法带有一个参数。
- promises(数组或者promise对象)
一个promise数组或者promise的hash。
all()方法返回单个promise,会执行一个数组或者一个散列的值。每个值会响应promise散列 中的相同序号或者键。如果任意一个promise被拒绝了,结果的promise也会被拒绝。
defer()
defer()方法创建了一个deferred对象,它没有参数,返回deferred对象的一个实例。
reject(reason)
这个方法创建了一个promise,被以某一原因拒绝执行了。它专门用于让我们能在一个promise 链中转发拒绝的promise,类似JavaScript中的throw。在同样意义上,我们能在JavaScript中捕获一 个异常,也能够转发这个拒绝,我们需要把这个错误重新抛出。可以通过$q.reject(reason)来 做到这点。
这个方法带有单个参数:
- reason(常量、字符串、异常、对象)
拒绝的原因。
reject()方法返回一个已经用某个原因拒绝的promise。
when(value)
when()函数把一个可能是值或者能接着then的promise包装成一个$q promise。这样我们就能处理一个可能是也可能不是promise的对象。
when()函数有一个参数:
- value
该参数是个值,或者是promise
when()函数返回了一个promise,我们可以像使用其他promise一样使用它。