zoukankan      html  css  js  c++  java
  • angular promise $q 异步调用

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

    背景

    首先说明一下promise异步调用出现的背景: 
    javascript语言是一种单线程模式,就是说一次只能够执行一个任务,如果有多个任务的话就必须排队,后面的任务要等待前面的任务完成之后才能进行下一个任务。这种单线程模式容易造成阻塞,因为如果队列中的某一个任务耗时长,后面的任务都无法快速执行,页面很容易卡在某一个状态上,用户体验差。因此javascript提供了异步模式来解决这种问题,主要有以下几种异步模式: 
    1.回调函数(callbacks) 
    2.事件监听 
    3.Promise对象 
    接下来讲一下回调函数,比如说下面的一串代码:

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

    如果用户登录成功,就会在success模块处理,如果登录失败,就会在error模块处理。 
    但是在任务多的情况下回调函数有以下几个问题: 
    1.回调使得调用不一致,调试很困难 
    2.每步调用之后都要显式的处理错误,否则处于回调和函数之间的错误报告非常容易丢失 
    3.代码很多很复杂,可读性和可维护性很差。 
    这时就要promise来处理问题了。

     

    为什么用promise呢? 
    1.使用promise可以让代码看上去像同步一样; 
    2.可以在程序的任何位置捕捉错误,并且绕过依赖于程序异常的后续代码,获得功能组合和错误冒泡的能力,最重要的是保持了异步运行的能力。 
    3.代码的可读性和可维护性都变得很好。

    怎么用Promise呢 
    要想在angular中使用Promise,就必须使用其内置的$q服务。来看一下$q。 
    $q跟angular的$rootscope模板集成的,所以在angular中执行和拒绝都很快。 
    $q promise是跟angularjs模板引擎集成的,这意味着在视图中找到任何promise都会在视图中被执行或拒绝。 
    那如何用$q来创建promise呢? 
    1.用$q的defer()方法创建一个deferred对象 
    2.用deferred对象的promise属性,就可以访问promise对象了。这个deferred对象还提供了三个方法:resolve(),reject(),notify() 
    见代码:

    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对象

    在promise中定义了三种状态:等待,完成,拒绝。 
    1. $q.defer() 
    在$q.defer()中,使用resolve方法可以变成完成状态,使用reject方法变成拒绝状态。 
    看一个简单的例子

    <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 id="flag" 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()方法。

    看一个例子,主要用了angular的路由,$http,promise异步调用。 
    项目结构: 
    Capture10.PNG-4.2kB 
    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

  • 相关阅读:
    团队绩效评估计划
    Beta阶段项目总结
    Alpha阶段项目总结
    Alpha版总结会议
    快上车项目简介(500字)
    第二阶段团队冲刺站立会议10
    第二阶段团队冲刺站立会议09
    第二阶段团队冲刺站立会议08
    第二阶段团队冲刺站立会议07
    第二阶段团队冲刺站立会议06
  • 原文地址:https://www.cnblogs.com/lyy-2016/p/8797406.html
Copyright © 2011-2022 走看看