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