【给你一个承诺 - 玩转 AngularJS 的 Promise】
了解Promise
在谈论Promise之前我们要了解一下一些额外的知识;我们知道JavaScript语言的执行环境是“单线程”,所谓单线程,就是一次只能够执行一个任务,如果有多个任务的话就要排队,前面一个任务完成后才可以继续下一个任务。
这种“单线程”的好处就是实现起来比较简单,容易操作;坏处就是容易造成阻塞,因为队列中如果有一个任务耗时比较长,那么后面的任务都无法快速执行,或导致页面卡在某个状态上,给用户的体验很差。
当然JavaScript提供了“异步模式”去解决上述的问题,关于“异步模式”JavaScript提供了一些实现的方法。
- 回调函数(callbacks)
- 事件监听
- Promise对象
关于回调函数,大家应该都不陌生,比如下面的代码(注:引用Leancloud上面的一点代码):
AV.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这个模块进行处理。
当我们需要处理的任务不是很多的情况下,使用回调函数还是可以应付的,也没有太大的问题,但是当我们需要处理的任务比较多的时候,使用回调函数的弊端越来越明显了;首先,回调使得调用不一致,得不到保证;当依赖于其它回调时,它们篡改代码的流程,是调试变得异常艰难,每一步调用之后都需要显式的处理错误;最后,过多的回调使得代码的可读性和可维护性都变得很差,所以越来越多的程序员选择使用Promise去处理异步模式。
关于Promise我们会在下面进行详细的说明。
Promise是什么
Promise是一种异步方式处理值(或者非值)的方法,promise是对象,代表了一个函数最终可能的返回值或者抛出的异常。
在与远程对象打交道时,Promise会非常有用,可以把它们看作远程对象的一个代理。
使用Promise的理由
- 使用
Promise可以让我们逃脱回调地狱,使我们的代码看起来像是同步的那样。 - 可以在程序中的任何位置捕捉错误,并且绕过依赖于程序异常的的后续代码,获得功能组合和错误冒泡的能力,最重要的是保持了异步运行的能力。
- 使我们的代码的可读性与可维护性都变得很好。
如何在AngularJS中使用Promise
要在AngularJS中使用Promise,要使用AngularJS的内置服务$q。
$q服务受到Kris Kowal的Q库的启发,所以类似于那个库,但是并没有包含那个库的所用功能。$q是跟AngularJS的$rootScope模板集成的,所以在AngularJS中执行和拒绝都很快。$q promise是跟AngularJS模板引擎集成的,这意味着在视图中找到任何Promise都会在视图中被执行或者拒绝。
我们可以先使用$q的defer()方法创建一个deferred对象,然后通过deferred对象的promise属性,将这个对象变成一个promise对象;这个deferred对象还提供了三个方法,分别是resolve(),reject(),notify()。
下面我们来通过代码逐步地将上面的功能都实现,毕竟说得再多,不如你实实在在地把它们敲成代码去实现。
Test1
我们先通过一个同步的例子来创建一个promise对象。
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>promise</title>
<script type="text/javascript" src="//cdn.bootcss.com/angular.js/1.5.8/angular.min.js"></script>
<script type="text/javascript" src="//cdn.bootcss.com/angular.js/1.5.8/angular-route.min.js"></script>
<script>
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){
alert("成功:"+result);
},function(error){
alert("失败:"+error);
});
if($scope.flag){
deferred.resolve("you are lucky!");
}else{
deferred.reject("sorry,it lost!");
}
}
}])
</script>
</head>
<body>
<div ng-app="myApp">
<div ng-controller="myController">
<label for="flag">成功
<input type="checkbox" id="flag" ng-model="flag"><br>
</label>
<hr>
<button ng-click="handle()">点击我</button>
</div>
</div>
</body>
</html>
效果演示:http://jsfiddle.net/gwfqga6m/
通过使用then进行链式请求
我们通过使用then方法来进行链式调用,这样做的好处是,无论前一个任务或者说then函数是被执行或者拒绝了都不会影响后面的then函数的运行。
我们可以通过then创建一个执行链,它允许我们中断基于更多功能的应用流程,可以借此导向不同的的结果,这个中断可以让我们在执行链的任意时刻暂停后者推迟promise的执行。
Test2
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>promise</title>
<script type="text/javascript" src="//cdn.bootcss.com/angular.js/1.5.8/angular.min.js"></script>
<script type="text/javascript" src="//cdn.bootcss.com/angular.js/1.5.8/angular-route.min.js"></script>
<script>
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);
}) if ($scope.flag) {
deferred.resolve("you are lucky!");
} else {
deferred.reject("sorry, it lost!");
}
}
}]);
</script>
</head>
<body>
<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>
</body>
</html>
效果演示:http://jsfiddle.net/gwfqga6m/1/
我们在Part1代码的基础上添加了一些代码,在原来的promise的链条上新添加了一个then()处理函数,目的就是为了创建一个执行连,看看在这条执行连上,promise是如何被执行的。
需要注意的一点是,在第一个then()方法中,我们在第一个successFunc函数中将result的值进行了改变,在第二个errorFunc函数中对error的值也进行了改变。
因为这个promise对象是贯穿整个执行链条的,所以在第一个then()方法中对其值进行改变必然会反映到后面的then()方法中
(未完待续...................................................................)
【给你一个承诺 - 玩转 AngularJS 的 Promise】的更多相关文章
- 给你一个承诺 - 玩转 AngularJS 的 Promise(转)
在谈论Promise之前我们要了解一下一些额外的知识:我们知道JavaScript语言的执行环境是“单线程”,所谓单线程,就是一次只能够执行一个任务,如果有多个任务的话就要排队,前面一个任务完成后才可 ...
- Angularjs,WebAPI 搭建一个简易权限管理系统 —— Angularjs名词与概念(一)
目录 前言 Angularjs名词与概念 Angularjs 基本功能演示 系统业务与实现 WebAPI项目主体结构 Angularjs 前端主体结构 2. 前言 Angularjs开发CRUD类型的 ...
- ”危险“的RESTRICT与GCC的编译优化(编程者对编译器所做的一个“承诺”:使用restrict修饰过的指针,它所指向的内容只能经由该指针修改)
restrict是C99标准中新添加的关键字,对于从C89标准开始起步学习C语言的同学来说(包括我),第一次看到restrict还是相当陌生的.Wikipedia给出的解释如下: In the C p ...
- 一起学习造轮子(一):从零开始写一个符合Promises/A+规范的promise
本文是一起学习造轮子系列的第一篇,本篇我们将从零开始写一个符合Promises/A+规范的promise,本系列文章将会选取一些前端比较经典的轮子进行源码分析,并且从零开始逐步实现,本系列将会学习Pr ...
- Angularjs,WebAPI 搭建一个简易权限管理系统 —— Angularjs 前端主体结构(五)
目录 前言 Angularjs名词与概念 Angularjs 基本功能演示 系统业务与实现 WebAPI项目主体结构 Angularjs 前端主体结构 6 Angularjs 前端主体结构 6.1 A ...
- 一招制敌 - 玩转 AngularJS 指令的 Scope (作用域),讲得特别好
学习了AngularJS挺长时间,最近再次回首看看指令这部分的时候,觉得比自己刚开始学习的时候理解的更加深入了,尤其是指令的作用域这部分. 步入正题: 每当一个指令被创建的时候,都会有这样一个选择,是 ...
- 贪玩ML系列之一个BP玩一天
手写串行BP算法,可调batch_size 既要:1.输入层f(x)=x 隐藏层sigmoid 输出层f(x)=x 2.run函数实现单条数据的一次前馈 3.train函数读入所有数据for循环处理 ...
- 玩转angularJs——通过自定义ng-model,不仅仅只是input可以实现双向数据绑定
体验更优排版请移步原文:http://blog.kwin.wang/programming/angularJs-user-defined-ngmodel.html angularJs双向绑定特性在开发 ...
- AngularJs $q promise
angularjs提供的$q服务是对Promises规范的一个实现.$q服务可以把一段异步的代码封装成同步的样式. 为啥是样式,因为异步还是异步,它并不会柱塞代码,只是看起来像同步代码. $q.whe ...
随机推荐
- [翻译]现代java开发指南 第三部分
现代java开发指南 第三部分 第三部分:Web开发 第一部分,第二部分,第三部分 =========================== 欢迎来到现代 Java 开发指南第三部分.在第一部分中,我们 ...
- Extensions in UWP Community Toolkit - Overview
概述 UWP Community Toolkit 中有一个 Extensions 的集合,它们可以帮助开发者实现很多基础功能,省去自己造轮子的过程,本篇我们先来看一下 Extensions 的功能都 ...
- Spring Security入门(3-2)Spring Security对接用户的权限系统
源文链接,多谢作者的分享: http://www.360doc.com/content/14/0727/16/18637323_397445724.shtml 1.原生的spring-security ...
- Pyhon之Django中的Form组件
Pyhon之Django中的Form组件 新手上路 Django的Form主要具有一下几大功能: 生成HTML标签 验证用户数据(显示错误信息) HTML Form提交保留上次提交数据 初始化页面 ...
- linux centos6.8 下安装mysql 步骤
安装环境:vmware12.centos6.8.centos中配置阿里云数据元 1.下载mysql 运行: sudo yum -y install mysql-server 如果下载失败,可以卸载重新 ...
- 关于css的层叠上下文和层叠顺序问题
关于css的层叠上下文和层叠样式问题 最近在项目中遇到了一个让我欲仙欲死的问题,我给项目中的图片设置了一个淡入效果,几opacity变化,但当我在它的上面有一个定位元素时,动画结束后,定位元素居然被遮 ...
- vue组件详解(五)——组件高级用法
一.递归组件 组件在它的模板内可以递归地调用自己, 只要给组件设置name 的选项就可以了. 示例如下: <div id="app19"> <my-compone ...
- Python/模块与包之模块
Python/模块与包之模块 1.什么是模块? 模块就是py文件 2.为什么要用模块? 如果在解释器上进行编码,把解释器关闭之前写的文件就不存在了,如果使用模块的话就能永久保存在磁盘中. 3.如何使用 ...
- Spring(四):Spring整合Hibernate,之后整合Struts2
背景: 上一篇文章<Spring(三):Spring整合Hibernate>已经介绍使用spring-framework-4.3.8.RELEASE与hibernate-release-5 ...
- [Linux]使用awk批量杀进程的命令
碰到需要杀掉某一类进程的时候,如何批量杀掉这些进程,使用awk命令是很好的选择. ps -ef|grep aaa|grep -v grep|awk '{print "kill -9 &quo ...