如何创建一个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一样使用它。