前面有说到处理angularjs中的异步的问题,在福瑞项目中我是通过逻辑判断不停的调用方法判断是否异步的按个函数已经执行完毕的。
这里咱们就来说下angularjs中的异步的问题,以及“正规的解决方法”
先聊一聊关于promise中的异步编程
异步编程存在两种形式,一种是单次执行模式,一种是监听执行模式。$q是解决第一种模式下的问题,promise模式的异步编程能够很好的解决单次执行模式下的一些问题,再说白一点,promise不会产生新的东西只是一个语法糖帮你能够编出更加优雅的异步代码
Promise模式使用一个延期对象defer代表异步执行体,用promise代表回调执行体,defer可以发送信息,promise可以接受信息,然后执行响应的回调函数。
说到这,是不是可以想到富瑞上面的那个问题可以把它们放到promise里进行链式调用了呢?我们继续往下说:
Promise是异步执行体和回调执行体之间的桥梁,这样的好处是异步执行体和回调执行体这种模式很好的对异步动作和回调动作进行了解耦。因为你可以在promise中好好的执行你的回调执行体,而只是接受一个defer发送来的参数。
这里还是没有很好的体现出promise模式的优势,而他真正的优势在于这种模式下扩充的api,。比如promise下的then方法,这种方法可以很好地支持异步链式编程。这里你可能还不了解,说下$q,$q是作为angularJs中的一个服务而存在的,只是对promise模式下异步的一个简单实现版(这里想到了华勤项目中小马哥用到的$q,当时还不好意思问这是啥!)关于$q的api大家可以从网上百度下、这里我就简单的说下
defer对象(延迟对象)可以通$q.defer()获取,下面是defer对象的api:
方法:resolve(value):向promise对象异步执行体发送消息告诉他我已经成功完成任务,value即为发送的消息。reject(value):向promise对象异步执行体发送消息告诉他我已经不可能完成这个任务了,value即为发送的消息。notify(value):向promise对象异步执行体发送消息告诉他我现在任务完成的情况,value即为发送的消息。
属性:promise即与这个defer对象的承诺对象。
从上可以看出defer主要是用来发送消息的。
promise对象可以通过defer.promise获取,下面是promise对象的api:
方法:
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中
defer():用来生成一个延迟对象 var defer =$q.defer();
reject():参数接收错误消息,相当于在回调函数中抛出一个异常,然后在下一个then中调用错误的回调函数。
all():参数接收为一个promise数组,返回一个新的单一promise对象,当这些promise对象对应defer对象全部解决这个单一promise对象才会解决,当这些promise对象中有一个被reject了,这个单一promise同样的被reject了
when():接收第一个参数为一个任意值或者是一个promise对象,其他3个同promise的then方法,返回值为一个promise对象。第一个参数若不是promise对象则直接运行success回调且消息为这个对象,若为promise那么返回的promise其实就是对这个promise类型的参数的一个包装而已,被传入的这个promise对应的defer发送的消息,会被我们when函数返回的promise对象所接收到。
对上面还有一个注意事项就是defer对象发送消息不会立即执行的,而是把要执行的代码放到了rootScope的evalAsync队列当中,当时scope.$apply的时候才会被promise接收到这个消息。
这里附上一份小马哥在华勤上写的一个代码,我加了些注释:
//请求服务器数据 functionmakeRequest($http,$q,url,params){ //$q是内置服务,所以可以直接使用 try{ vardefered=$q.defer();//声明延后执行,表示要去监控后面的执行 $http.get(url,params) .success(function(data,status,headers){ //Dosomethingsuccessful defered.resolve(data);//声明执行成功,即http请求数据成功,可以返回数据了 }) .error(function(data,headers){ //Handletheerror defered.reject(status+data);//声明执行失败,即服务器返回错误 }); returndefered.promise;//返回承诺,这里并不是最终数据,而是访问最终数据的API }catch(error){ alert("连接服务发生意外错误"); } }
下面是对应的调用:
promise.then(function(data){//调用承诺API获取数据.resolve $scope.user=data; },function(data){//处理错误.reject $scope.user={error:'用户不存在!'}; });
最后来说明下关于实现angularjs中的同步请求的三种解决方法
解决方法一:
$http.get('url1').success(function(d1){ $http.get('url2').success(function(d2){ //处理逻辑 }); });
解决方法二:
then中的方法会按顺序执行。
varapp=angular.module('app',[]); app.controller('promiseControl',function($scope,$http){ functiongetJson(url){ vardeferred=$q.defer(); $http.get(url) .success(function(d){ d=parseInt(d); console.log(d); deferred.resolve(d); }); returndeferred.promise; } getJson('json1.txt').then(function(){ returngetJson('json2.txt'); }).then(function(){ returngetJson('json1.txt'); }).then(function(){ returngetJson('json2.txt'); }).then(function(d){ console.log('end'); }); });
解决方法三
$q.all方法第一个参数可以是数组(对象)。在第一参数中内容都执行完后就会执行then中方法。第一个参数的方法的所有返回值会以数组(对象)的形式传入。
varapp=angular.module('app',$http){ $q.all({first:$http.get('json1.txt'),second:$http.get('json2.txt')}).then(function(arr){ console.log(arr); angular.forEach(arr,function(d){ console.log(d); console.log(d.data); }) }); });原文链接:https://www.f2er.com/angularjs/148735.html