Angular通信$q服务和promise对象

promise

约定(promise)是一个对象,表示在未来时间点会发生的某件事情,约定可以是三种状态之一:等待、完成或拒绝。约定将从等待状态开始,然后可以转换为完成或者拒绝状态,一旦约定完成或者被拒绝,它就无法再改变状态。例如我们的$http服务返回的就是一个经过包装的promise对象。


可以看到,黑色部分圈起来的是基本的promise部分,此外$http还提供了success和error的语法糖,我们完全也可以直接使用then方法。

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

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

    });
这里的then方法定义了未来的某个要执行的回调函数,当promis通过某个方法转换到完成或者拒绝状态时,回调函数就会被调用,在下面说$q服务的时候会详细介绍。

then方法会返回一个promise对象,所以可以链式调用,另外它返回的值会传递给下一个then函数。

promiseA
   .then(function(val){$log.info(val);return ++val;})
   .then(function(val){$log.info(val);return ++val;})
   .then(
         function(val){$log.info(val);return ++val;},
         function(val){$log.info(val)}
   );
如果第一个then传入的val = 1,那么最终输入:1,2,3。



$q服务
$q服务有4个方法函数

  1. $q.defer(),返回一个deferred对象。
  2. $q.reject(),返回一个失败原因,promise.then()执行失败回调。
  3. $q.all(promises),多个promise必须执行成功,才能执行成功回调,传递值为数组或哈希值,数组中每个值为与Index对应的promise对象。
  4. $q.when(value),传递变量值,promise.then()执行成功回调。
调用$q.defer()对象返回一个deferred对象,这个对象是我们最常用的,打印出来看一下是什么东西。

可以看到它有3个方法:resolve,reject,notify,分别对应于接受、拒绝、通知。还有一个promise属性,它的值就是一个基本的promise对象。
  • resolve用来解决一个promise,也就是把promise转换成完成状态。
  • reject用来拒绝一个promise,也就是把promise转换成拒绝状态。
  • notify用于promise执行时更新状态,用来显示进度之类的。
/ 为了演示的目的,此处我们假设 `$q`, `scope` 以及 `okToGreet` 引用 在当前执行环境中可用  
// (比如他们已经被注入,或者被当做参数传进来了).  
   
function asyncGreet(name) {  
  var deferred = $q.defer();  
   
  setTimeout(function() {  
    // 因为此function 在未来的事件循环中异步执行,  
    // 我们需要把代码包装到到一个 $apply 调用中,以便正确的观察到 model 的改变  
    scope.$apply(function() {  
      deferred.notify('即将问候 ' + name + '.');  
   
      if (okToGreet(name)) {  
        deferred.resolve('你好, ' + name + '!');  
      } else {  
        deferred.reject('拒绝问候 ' + name + ' .');  
      }  
    });  
  }, 1000);  
   
  return deferred.promise;  
}  
   
var promise = asyncGreet('小漠漠');  
promise.then(function(greeting) {  
  alert('成功: ' + greeting);  
}, function(reason) {  
  alert('失败鸟: ' + reason);  
}, function(update) {  
  alert('收到通知: ' + update);  
});  
链式调用内部的默认失败回调会向后传递异常,所以为避免麻烦,且不在意每一处的业务逻辑错误,不要在每一处 then() 处声明异常处理函数,在最后一个 then()中声明即可。
var deferred = $q.defer();
    deferred.resolve(1);
var promiseA = deferred.promise;
promiseA
   .then(function(val){$log.info(val);return ++val;})
   .then(function(val){$log.info(val);return ++val;})
   .then(
         function(val){$log.info(val);return ++val;},
         function(val){$log.info(val)}
   );
链式调用完成后控制台打印出 1,2,3
var deferred = $q.defer();
    deferred.resolve(1);
var promiseA = deferred.promise;
promiseA
   .then(function(val){$log.info(val);return $q.reject(15);})
   .then(function(val){$log.info(val);return ++val;})
   .then(function(val){$log.info(val);return ++val;})
   .then(function(val){$log.info(val);return ++val;})
   .then(
         function(val){$log.info(val);return ++val;},
         function(val){$log.info(val)}
   );
链式调用完成后控制台打印出 1,15,可以看出,第一个 return $q.reject(15)之后,直到最后一个 then()才有错误回调函数,所以异常一直传递到最后,中间的几个 then()没有错误回调函数。

下面演示一个when和all的调用
var promiseA = $q.when('I Love you!');
 var promiseB = $q.when('Love story!');
 var promiseC = $q.when("Let't get wet!");
 $q.all([promiseA,promiseB,promiseC]).then(function(value){
    value[0].then(function(value){$log.info(value);})
    value[1].then(function(value){$log.info(value);})
    value[2].then(function(value){$log.info(value);})
 }) 

$q服务的具体使用例子
我们知道,在AngularJS的MVC框架之中,业务逻辑(包括网络请求)的部分应该尽可能写到Service层中,而让Controller的逻辑尽可能少。但是,怎么把网络请求最终得到的有用的数据,返回给controller呢?
我们可以在Service中返回一个自定义的promise对象,用来回调给controller。这里的回调者,由$q创建的“defered”对象来担任。

service.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对象返回出来
        };
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);
        }

    }])



参考链接:
http://blog.csdn.net/renfufei/article/details/19174015




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值