文章参考
http://www.jb51.net/article/61638.htm
http://www.cnblogs.com/xing901022/p/4928147.html
Promise
Promise是一种模式,以同步操作的流程形式来操作异步事件,避免了层层嵌套,可以链式操作异步事件。
我们知道,在编写javascript异步代码时,callback是最最简单的机制,可是用这种机制的话必须牺牲控制流、异常处理和函数语义化为代价,甚至会让我们掉进出现callback大坑,而promise解决了这个问题。
ES6中Promise、angularJS内置的AngularJS内置Q,以及when采用的都是Promises/A规范,如下:
每个任务都有三种状态:未完成(pending)、完成(fulfilled)、失败(rejected)。
1.pending状态:可以过渡到履行或拒绝状态。
2.fulfilled状态:不能变为其他任何状态,而且状态不能改变,必须有value值。
3.rejected状态:不能变为其他任何状态,而且状态不能改变,必须有reason。
状态的转移是一次性的,状态一旦变成fulfilled(已完成)或者failed(失败/拒绝),就不能再变了。
$q服务
q服务是AngularJS中自己封装实现的一种Promise实现,相对与Kris Kwal's Q要轻量级的多。
先介绍一下$q常用的几个方法:
defer() 创建一个deferred对象,这个对象可以执行几个常用的方法,比如resolve,reject,notify等
all() 传入Promise的数组,批量执行,返回一个promise对象
when() 传入一个不确定的参数,如果符合Promise标准,就返回一个promise对象。
案例
function okToGreet(name){ return name === 'Robin Hood'; } function asyncGreet(name) { var deferred = $q.defer(); setTimeout(function() { // 因为这个异步函数fn在未来的异步执行,我们把代码包装到 $apply 调用中,一边正确的观察到 model 的改变 $scope.$apply(function() { //执行promise.then的第三个参数(notifyCallback)方法 deferred.notify('About to greet ' + name + '.'); if (okToGreet(name)) { //执行promise.then的第一个参数(successCallback)方法 deferred.resolve('Hello, ' + name + '!'); } else { //执行promise.then的第二个参数(errorCallback)方法 deferred.reject('Greeting ' + name + ' is not allowed.'); } }); }, 1000); return deferred.promise; } var promise = asyncGreet('Robin Hood'); promise.then(function(greeting) { alert('Success: ' + greeting); }, function(reason) { alert('Failed: ' + reason); }, function(update) { alert('Got notification: ' + update); });
Promise API
当创建 deferred 实例时会创建一个新的 promise 对象,并可以通过 deferred.promise 得到该引用。
promise 对象的目的是在 deferred 任务完成时,允许感兴趣的部分取得其执行结果。
promise 对象的方法
then(successCallback,errorCallback,notifyCallback):参数为不同消息下的不同回调函数,defer发送不同的消息执行不同的回调函数,消息作为这些回调函数的参数传递。返回值为回一个promise对象为支持链式调用而存在。当第一个defer对象发送消息后,后面的promise对应的defer对象也会发送消息,但是发送的消息不一样,不管第一个defer对象发送的是reject还是resolve,第二个及其以后的都是发送的resolve,消息是可传递的。
catch(errorCallback):then(null,errorCallback)的缩写。
finally(callback):相当于then(callback,callback)的缩写,这个finally中的方法不接受参数,却可以将defer发送的消息和消息类型成功传递到下一个then中。
下面是自己工作中写的例子——两个异步请求,如何按照顺序执行(异步请求同步处理)
/** * 进入页面的控制器 controller * */ angular.module("hkApp").controller("salesGoodsTop10Controller", ["$scope", "$state",'salesGoodsTop10Service', function ($scope, $state,salesGoodsTop10Service) { //第一步,获取前十的商品list var promise = salesGoodsTop10Service.getSalesGoodsStatisticsList(); promise.then(function(returnData){ $scope.lists = returnData.data; //第二步,获取商品的总数量,返回的是promise对象,作为第二个then的执行方法 return salesGoodsTop10Service.getGatherTotal(); }).then(function(returnData){ $scope.gatherTotal = returnData.data; }); $scope.goBack = function(){ window.history.back(); }; }]); /** * 向服务器发送请求的服务 service * */ angular.module("hkApp").factory("salesGoodsTop10Service",["$http","$q",function($http,$q){ /** * 获取商品前10的商品 * */ var getSalesGoodsStatisticsList = function (){ var deferred = $q.defer(); var url = "/index.php/Admin/GatherGoods/gatherGoodsTop.html"; var params = { "top":5 }; $http.post(url,params) .success(function(response, status, headers, config){ if(response.status == 1){ deferred.resolve(response); } }); return deferred.promise; }; /** * 获取销售商品总数 * */ var getGatherTotal = function (){ var deferred = $q.defer(); var url = "/index.php/Admin/GatherGoods/gatherTotal.html"; $http.post(url) .success(function(response, status, headers, config){ if(response.status == 1){ deferred.resolve(response); } }); return deferred.promise; }; var resultJson = { "getSalesGoodsStatisticsList":getSalesGoodsStatisticsList, "getGatherTotal":getGatherTotal }; return resultJson; }]);