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异步调用。
项目结构:
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
angular promise $q 异步调用的更多相关文章
- angular指令,异步调用数据,监控数据的变化(自定义一个表头的指令)
angular框架中提供了很多有效的指令,指令的目的就是为了提高代码的复用率,提高工作效率. 下面我们自己来定义一个指令: 一点建议:写指令名字的时候,尽量不要用用大写,下划线等,否则会有很大的坑等着 ...
- 浅谈Angular的 $q, defer, promise
浅谈Angular的 $q, defer, promise 时间 2016-01-13 00:28:00 博客园-原创精华区 原文 http://www.cnblogs.com/big-snow/ ...
- angular的$q服务和promise模式
此承诺/延迟(promise/deferred)实现的灵感来自于 Kris Kowal's Q CommonJS Promise建议文档 将承诺(promise) 作为和 异步执行操作(action) ...
- JS常用方法总结,及jquery异步调用后台方法实例
//前台接收get参数值 function getQueryString(name) { var queryStrings = window.location.search.sp ...
- WinForm查询大数据界面假死,使用异步调用解决
用DataGridView无分页绑定一个几千条数据的查询,查询的时候界面直接卡死十几秒,用户体验非常不好,因此用异步操作解决界面卡死的问题原本场景:点击[查询]后,界面直接卡死优化场景:点击[查询]后 ...
- 并发编程 - 线程 - 1.线程queue/2.线程池进程池/3.异步调用与回调机制
1.线程queue :会有锁 q=queue.Queue(3) q.get() q.put() 先进先出 队列后进先出 堆栈优先级队列 """先进先出 队列"& ...
- Python并发编程06 /阻塞、异步调用/同步调用、异步回调函数、线程queue、事件event、协程
Python并发编程06 /阻塞.异步调用/同步调用.异步回调函数.线程queue.事件event.协程 目录 Python并发编程06 /阻塞.异步调用/同步调用.异步回调函数.线程queue.事件 ...
- 抓到Dubbo异步调用的小BUG,再送你一个贡献开源代码的机会
hello,大家好呀,我是小楼. 最近一个技术群有同学at我,问我是否熟悉Dubbo,这我熟啊~ 他说遇到了一个Dubbo异步调用的问题,怀疑是个BUG,提到BUG我可就不困了,说不定可以水,哦不.. ...
- C#委托异步调用
参考页面: http://www.yuanjiaocheng.net/webapi/mvc-consume-webapi-get.html http://www.yuanjiaocheng.net/w ...
随机推荐
- 【JavaScript】particle
这是js实现的粒子动画,有两种模式,分别是zoom和line,它们对应的效果不同,但是原理都相同,具体分析如下: 部分程序如下: var p = this; p.originParams = orig ...
- pyenv 配置python虚拟环境
安装pyenv环境 yum -y install git yum install gcc make patch gdbm-devel openssl-devel sqlite-devel readli ...
- angularjs ng-if ng-show ng-hide区别
在使用anularjs开发前端页面时,常常使用ng-show.ng-hide.ng-if功能来控制页面元素的显示或隐藏,那他们之间有什么不同呢? 实现原理方面:ng-show/ng-hide是通过修改 ...
- Linux文件目录命令
Linux文件目录命令 pwd,查看当前工作目录的完整路径 pwd:/root ls,用来打印当前目录的清单,可以指定其他目录 -a:列出目录下所有的文件,包括以"."开头的隐藏文 ...
- linux中安装jdk以及eclipse的安装
最近将系统换成了linux(ubuntu14.04),随之而来的是各种软件的配置,环境的配置,因此趁机将自己的过程整理出来. 1:linux中怎么安装jdk 1 首先现在jdk源文件http://ww ...
- How RTT works
13.2 How RTT works 13.2.1 Target implementation Real Time Terminal uses a SEGGER RTT Control Block s ...
- emmet完整收录(html,css)
emmet官网 https://emmet.io/ 语法篇 Child: > nav>ul>li <nav> <ul> <li></li&g ...
- Oracle 使用RMAN进行备份
备份理论和基本语法 备份概念 执行备份或还原草的数据库称为目标.在一些环境下,有许多数据库,因此有许多RMAN目标.应一次连接每个数据库.目标的每个备份都有一些属性: 打开或关闭 完整或部分 完整或增 ...
- cmd命令操作Mysql数据库
在一次考试中,笔者因考试的电脑上没有安装操作Mysql数据库的可视化工具而不知如何操作数据库,所以在这里可以提醒各位掌握 命令行来操作数据库也是非常重要的. 笔者以惨痛的教训来警惕大家. 进入正题: ...
- nginx 源码安装以及后续升级https
事情的来源是,公司要将网站从http升级到https,由于历史遗留原因,才发现现有的nginx是通过源码安装的,并没有安装ssl模块,需要现安装sll模块,这个nginx是整个公司最前端的一个代理,涉 ...