使用promise相较于ajax的优势(Angularjs $q 为例)
2015-11-25 16:15
676 查看
一般在WEB开发时总会涉及到从服务器调用接口的操作,为了不影响用户操作,一般会使用异步方式执行,从而不阻塞用户的界面操作。而一些常用的调用服务会封装成独立模块供使用。这时候就会遇到一些问题。比如:若所有服务内的方法都是异步方式的,则如何在外部控制两个异步任务的顺序?如何较为统一地处理超时以及执行异常的状况?…等等
直到后来看到了
在上述场景中
需要强调的是:若在
参考angular的post请求,SpringMVC后台接收不到参数值的解决方案将postType从
在angular模块中进行配置,如下:
这样有可能出现在得到用户信息前就调用getPermission()方法,这样逻辑就有问题就出错。但是如果必须要在获得用户信息后申请权限,则要么把getUser()取消异步,这样会影响界面响应。要么:
这样一层一层嵌套两个函数还好,如果在多了foo(), bar()。。。那代码就很难看了。
调用时候,直接
或者:
这样就可以做到多个promise的结果与函数传入参数的一一对应。
要做到依次执行则使用如下代码:
若一个长时间获取资源的方法仅需在第一次执行的时候从服务器获取,下次直接从本地缓存获得,就可以用如下结构:
这样的好处在于只有在用户第一次发起请求时才会从服务器获取,在本地有缓存的时候,就直接返回缓存数据。
同时可以在用户在短时间频繁发起请求,而本地还没有缓存时候,避免多次发起服务器请求的情况(这时候返回的认识promise即变量p)。
直到后来看到了
$q…
异步操作
异步操作有一般使用 jQuery的ajax,本文结合AngularJs,因此也顺带引入Angular的$http服务。
ajax
ajax的常用写法如下:$.ajax({ type:'post',//or 'get' url:'api/foo', data:{'a':'v'}, async:true, //or false success:function(response){ parseResponse(response); }, error:function(err){ handleError(err); } })
在上述场景中
async决定了ajax是否阻塞界面进程。若asycn=false,则在请求过程中用户界面无响应,反之无影响。
需要强调的是:若在
async=true情况下更新Angular的$scope中的数据,应该调用
$scope.$apply()来手动完成刷新
$http
基本使用
angular中的$http默认均为异步执行,同时与
$scope的刷新不冲突。常用方式如下:
/** * @param method:post,get..... * @param url:api REST路径 * @param data:封装在request请求中的参数 * @param param:写在url路径后面的参数'?param=v¶m2=v2...' * @param timeout:超时时间 */ $http({method:'POST', url:url, data:data, param:param, timeout:5000}) .success(function(response){ parseResponse(response); }) .error(function(err,stat){ handleErr(err); });
[附]post的问题
若直接使用AngularJs 的$http post请求在SpringMVC中通过@RequestParams是拿不到值的。
参考angular的post请求,SpringMVC后台接收不到参数值的解决方案将postType从
application/json改成
application/x-www-form-urlencoded即可。
在angular模块中进行配置,如下:
app.config(function($httpProvider) { $httpProvider.defaults.headers.put['Content-Type'] = 'application/x-www-form-urlencoded'; $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'; // Override $http service's default transformRequest $httpProvider.defaults.transformRequest = [function(data) { /** * The workhorse; converts an object to x-www-form-urlencoded serialization. * @param {Object} obj * @return {String} */ var param = function(obj) { var query = ''; var name, value, fullSubName, subName, subValue, innerObj, i; for (name in obj) { value = obj[name]; if (value instanceof Array) { for (i = 0; i < value.length; ++i) { subValue = value[i]; fullSubName = name + '[' + i + ']'; innerObj = {}; innerObj[fullSubName] = subValue; query += param(innerObj) + '&'; } } else if (value instanceof Object) { for (subName in value) { subValue = value[subName]; fullSubName = name + '[' + subName + ']'; innerObj = {}; innerObj[fullSubName] = subValue; query += param(innerObj) + '&'; } } else if (value !== undefined && value !== null) { query += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&'; } } return query.length ? query.substr(0, query.length - 1) : query; }; return angular.isObject(data) && String(data) !== '[object File]' ? param(data) : data; }]; });
直接异步遇到的问题
如果有一个需求需要先获取用户信息(如getUser()),之后获取用户权限(如
getPermission())。假设两个方法都是异步的,那在直接调用的时候:
getUser(); getPermission();
这样有可能出现在得到用户信息前就调用getPermission()方法,这样逻辑就有问题就出错。但是如果必须要在获得用户信息后申请权限,则要么把getUser()取消异步,这样会影响界面响应。要么:
function getUser(getPermission){ $.ajax({ ... .success(function(user){ getPermission(user); }) }) }
这样一层一层嵌套两个函数还好,如果在多了foo(), bar()。。。那代码就很难看了。
承诺与延迟
再一次~~~对于$q的教程,若有梯子的同学,强烈建议看看这个视频 The Power of
$qby Dave Smith at ng-europe 2014
$q的基本使用
$q主要是在
$http的外围包上一个q承诺(promise),同时把$http结果用q.promise处理,然后直接返回q.promise就好了。
var defered= $q.defer(); $http({method:'POST', url:'api/url', data:{data}, timeout:5000}) .success(function(response){ defered.resolve(response); }) .error(function(err,status){ if(status === 405){ defered.reject('internal error'); } else if(status === -1){ defered.reject('timeout'); } else { defered.reject('other error'); } }); return defered.promise;
调用时候,直接
promise.then()如下:
service.getPromise().then( function(result){ //resolve的数据 parseResult(result); }, function(err){ //reject的错误 handleErr(err); } //function(){ // //defered.notify()//一般不常用,可以多次调用notify // handlePregress(); //} );
优势
可以在调用时在决定每个promise的异步或者同步。方便组织
同时执行多个异步任务的方法如下:var promises = [promise1, promise2] $q.all(promises).then(function(responses));
或者:
var promises = [promise1, promise2] $q.all(promises).then( spread(function(return1, return2){}) )
这样就可以做到多个promise的结果与函数传入参数的一一对应。
要做到依次执行则使用如下代码:
promise1.then(function(){ promise2.then(functin(){}) })
$q.when()
作为缓存方法
若一个长时间获取资源的方法仅需在第一次执行的时候从服务器获取,下次直接从本地缓存获得,就可以用如下结构:app.factory('movie', function($q,$http){ var cached, p; return { getMovie:function(){ return $q.when(cached || p || helper()); } }; function helper(){ var defered = $q.defer(); p = defered.promise; $http({method:'get', url:url}) .success(function(movie){ cached = movie; defered.resolve(movie); }); return defered.promise; } });
这样的好处在于只有在用户第一次发起请求时才会从服务器获取,在本地有缓存的时候,就直接返回缓存数据。
同时可以在用户在短时间频繁发起请求,而本地还没有缓存时候,避免多次发起服务器请求的情况(这时候返回的认识promise即变量p)。
相关文章推荐
- JQuery1——基础($对象,选择器,对象转换)
- JavaScript演示排序算法
- 2015-2016网页设计趋势分析 Web Design of Trends
- jQuery Ajax 跨域调用
- 移动端的长按事件
- jquery教程靠边站,一分钱不花让你免费学会jquery
- JQuery+Strusts1.x无刷新登录
- JavaScript 各种遍历方式详解
- 解决Ajax悬停效果,无法遮蔽FLASH的问题
- 再谈Jquery Ajax方法传递到action(补充)
- jQuery菜单插件用法实例
- JQuery 初体验(建议学习jquery)
- 基于Jquery和CSS3制作数字时钟附源码下载(CSS3篇)
- Jquery实现的table最后一行添加样式的代码
- jQuery实现向下滑出的平滑下拉菜单效果
- jQuery 练习[一] 学习jquery的准备工作
- jquery获得页面元素的坐标值实现思路及代码
- 使用Browserify配合jQuery进行编程的超级指南
- jquery如何实现在加载完iframe的内容后再进行操作
- jquery $.ajax()取xml数据的小问题解决方法