angular promise $q 异步调用

Angular异步调用 Promise和$q的用法

背景

接下来讲一下回调函数,比如说下面的一串代码:

User.logIn("myname", "mypass", {
    success: function(user) {
        // Do stuff after successful login.
    },
    error: function(user, error) {
        // The login failed. Check error to see why.
    }
});

这时就要promise来处理问题了。

3.代码的可读性和可维护性都变得很好。

见代码:

var example = function showExample() {  
     var deferred = $q.defer(); 
     
     //如果成功
     deferred.resolve("get example"); 
       
     //如果失败
     deferred.reject('get example failure');
     
     //包装好一个 promise 返回给调用方
     return deferred.promise;
     
}

$q服务

$q是angular自己封装的一种promise实现,$q的常用的几个方法:

方法用途
$q.defer()创建一个deferred对象,这个对象可以执行几个常用的方法,如resolve,reject,notify等
$q.all()传入promise数组,批量执行,返回一个promise对象
$q.when()传入一个不确定的参数,如果符合promise标准,就返回一个promise对象

看一个简单的例子

<html ng-app="myApp">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <script src="http://apps.bdimg.com/libs/angular.js/1.2.16/angular.min.js"></script>
</head>
<body>
    <div ng-controller="myctrl">
        {{test}}
    </div>
    <script type="text/javascript">
         var myAppModule = angular.module("myApp",[]);
         myAppModule.controller("myctrl",["$scope","$q",function($scope, $ q ){
        
            //通过$q服务注册一个延迟对象 defer1
            var defer1 = $q.defer();
            //生成一个promise对象
            var promise1 = defer1.promise;

            promise1
            .then(function(value){
                console.log("in promise1 ---- success");
                console.log(value);
            },function(value){
                console.log("in promise1 ---- error");
                console.log(value);
            },function(value){
                console.log("in promise1 ---- notify");
                console.log(value);
            });
            
            //resolve方法说明promise.then()会进入第一个function
            defer1.resolve("hello");
            //reject方法说明promise.then()会进入第二个function
            defer1.reject("sorry,reject");
            
         }]);
    </script>
</body>
</html>

promise.then()支持链式调用,里面的三个方法用来监听一个promise的不同状态:

promise.then(function(data){
    //success callback
},function(err){
    //error callback
},function(update){
    //unfulfilled callback
}

不过我们一般只监听success和error的情况。

2.$q.all()

这个用的很少,一般用于批量执行,举个例子:

var funcA = function(){
    console.log("funcA");
    return "hello,funA";
}
var funcB = function(){
    console.log("funcB");
    return "hello,funB";
}

$q.all([funcA(),funcB()])
    .then(function(result){
        console.log(result);
});

看一下执行结果:

funcA
funcB
Array [ "hello,funA", "hello,funB" ] 

3.$q.when()

when方法中可以传入一个参数,这个参数可能是一个值,可能是一个符合promise标准的外部对象。当传入的参数不确定时,可以使用这个方法。

var funcA = function(){
    console.log("funcA");
    return "hello,funA";
}
$q.when(funcA())
    .then(function(result){
        console.log(result);
    });

结果: hello,funA

Promise

promise可以通过then方法来实现链式调用,这样的好处是无论前一个任务是否成功执行,都不会影响后面的then函数运行。

看一个简单的例子:

<div ng-app="MyApp">
    <div ng-controller="MyController">
        <label for="flag">成功
        <input  type="checkbox" ng-model="flag" /><br/>
        </label>
        <div ng-cloak>
            {{status}}
        </div>
        <hr/>
        <button ng-click="handle()">点击我</button>
    </div>
</div>
angular.module("MyApp", [])
        .controller("MyController", ["$scope", "$q", function ($scope, $q) {
            $scope.flag = true;
            $scope.handle = function () {
            var deferred = $q.defer();
            var promise = deferred.promise;

            promise.then(function (result) {
                result = result + "you have passed the first then()";
                $scope.status = result;
                return result;
            }, function (error) {
                error = error + "failed but you have passed the first then()";
                $scope.status = error;
                return error;
            }).then(function (result) {
                alert("Success: " + result);
            }, function (error) {
                alert("Fail: " + error);
            })

            //这里的$scope.flag根据复选框的勾选情况而变化
            if ($scope.flag) {
                //如果选中,defer用resolve并添加数据,promise的then就会进入function 1,,修改页面status的值,进入第二个then,弹出在第一个then里返回的result值。
                deferred.resolve("you are lucky!");
            } else {
                deferred.reject("sorry, it lost!");
            }
        }
}]);

值得注意的是,在第一个then()方法中对result值进行了改变,改变后的值是会反映到后面的then()方法中的。因为promise对象贯穿了整个执行链条,前面then()方法的修改会影响后面的then()方法。

js/app.js

angular.module("MyApp", ["ngRoute","MyController", "MyService"])
.config(["$routeProvider", function($routeProvider){
    $routeProvider
    .when('/',{
        templateUrl: "views/home.html",
        controller: "IndexController"
    });
}]);

js/controller.js

angular.module("MyController", [])
    .controller("IndexController", ["$scope", "githubService",                                function($scope, githubService){
        $scope.name = "dreamapple";
        $scope.show = true;
        githubService.getPullRequests().then(function(result){
            $scope.data = result;
        },function(error){
            $scope.data = "error!";
        },function(progress){
            $scope.progress = progress;
            $scope.show = false;
        });
    }]);

js/service.js

angular.module("MyService", [])
    .factory('githubService', ["$q", "$http", function($q, $http){
        var getPullRequests = function(){
            var deferred = $q.defer();
            var promise = deferred.promise;
            var progress;
            $http.get("https://api.github.com/repos/angular/angular.js/pulls")
                .success(function(data){
                    var result = [];
                    for(var i = 0; i < data.length; i++){
                        result.push(data[i].user);
                        progress = (i+1)/data.length * 100;
                        deferred.notify(progress);
                    }
                    deferred.resolve(result);
                })
                .error(function(error){
                    deferred.reject(error);
            });
            return promise;
        }

        return {
            getPullRequests: getPullRequests
        };
    }]);

views/home.html

<h1>{{name}}</h1>
<h2>Progress: {{progress}}</h2>
<h3 ng-show="show">Please wait a moment...</h3>
<p ng-repeat="person in data">{{person.login}}</p>

index.html

<body ng-app="MyApp">
    <header>
        <h1>Header</h1>
        <hr/>
    </header>
    <div ng-view>
    </div>
    <footer>
        <hr/>
        <h1>Footer</h1>
    </footer>
</body>

上面的例子参考了: https://segmentfault.com/a/1190000002788733