了解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更多的信息

  • Promises/A+
  • Promises/A

使用Promise的理由

  • 使用Promise可以让我们逃脱回调地狱,使我们的代码看起来像是同步的那样。
  • 可以在程序中的任何位置捕捉错误,并且绕过依赖于程序异常的的后续代码,获得功能组合和错误冒泡的能力,最重要的是保持了异步运行的能力。
  • 使我们的代码的可读性与可维护性都变得很好。

如何在AngularJS中使用Promise

要在AngularJS中使用Promise,要使用AngularJS的内置服务$q

  • $q服务受到Kris Kowal的Q库的启发,所以类似于那个库,但是并没有包含那个库的所用功能。
  • $q是跟AngularJS$rootScope模板集成的,所以在AngularJS中执行和拒绝都很快。
  • $q promise是跟AngularJS模板引擎集成的,这意味着在视图中找到任何Promise都会在视图中被执行或者拒绝。

我们可以先使用$qdefer()方法创建一个deferred对象,然后通过deferred对象的promise属性,将这个对象变成一个promise对象;这个deferred对象还提供了三个方法,分别是resolve(),reject(),notify()

下面我们来通过代码逐步地将上面的功能都实现,毕竟说得再多,不如你实实在在地把它们敲成代码去实现。

Test1

我们先通过一个同步的例子来创建一个promise对象。

HTML代码:

<div ng-app="MyApp"><div ng-controller="MyController"><label for="flag">成功<input id="flag" type="checkbox" ng-model="flag" /><br/></label><hr/><button ng-click="handle()">点击我</button></div>
</div>

JS代码:

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("Success: " + result);}, function (error) {alert("Fail: " + error);});if ($scope.flag) {deferred.resolve("you are lucky!");} else {deferred.reject("sorry, it lost!");}}
}]);

我们来详细的分析一下上面的代码,我们在html页面上添加了一个checkbox,一个button目的是为了当我们选中checkbox和不选中checkbox时,点击下面的按钮会弹出不同的内容。

var deferred = $q.defer()这段代码创建了一个deferred对象,我们然后利用var promise = deferred.promise创建了一个promise对象。

我们给给promisethen方法传递了两个处理函数,分别处理当promise被执行的时候以及promise被拒绝的时候所要进行的操作。

下面的一个if(){}else{}语句块,包含执行和拒绝deferred promise,如果$scope.flagtrue,那么我们就会执行deferred promise,然后我们给promise传递一个值,也可能是一个对象,表明promise执行的结果。如果$scope.flagfalse,那么我们就会拒绝deferred promise,然后我们给promise传递一个值,也可能是一个对象,表明promise被拒绝的原因。

现在回过头来看看,promisethen方法,如果promise被执行,那么它的参数中的第一个函数的result就代表了"you are lucky!"

我们暂时用的是同步的模式,为的是能够说明问题,后面将会使用异步的方法。

到这里我们可以了解一下$qdefer()方法创建的对象具有哪些方法

  • resolve(value):用来执行deferred promisevalue可以为字符串,对象等。
  • reject(value):用来拒绝deferred promisevalue可以为字符串,对象等。
  • notify(value):获取deferred promise的执行状态,然后使用这个函数来传递它。
  • then(successFunc, errorFunc, notifyFunc):无论promise是成功了还是失败了,当结果可用之后,then都会立刻异步调用successFunc,或者'errorFunc',在promise被执行或者拒绝之前,notifyFunc可能会被调用0到多次,以提供过程状态的提示。
  • catch(errorFunc)
  • finally(callback)

Online Code Part1

通过使用then进行链式请求

我们通过使用then方法来进行链式调用,这样做的好处是,无论前一个任务或者说then函数是被执行或者拒绝了都不会影响后面的then函数的运行。

我们可以通过then创建一个执行链,它允许我们中断基于更多功能的应用流程,可以借此导向不同的的结果,这个中断可以让我们在执行链的任意时刻暂停后者推迟promise的执行。

Test2

HTML代码

<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>

JS代码:

        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!");}}
}]);

Online Code Part2  点击预览

我们在Part1代码的基础上添加了一些代码,在原来的promise的链条上新添加了一个then()处理函数,目的就是为了创建一个执行连,看看在这条执行连上,promise是如何被执行的。

需要注意的一点是,在第一个then()方法中,我们在第一个successFunc函数中将result的值进行了改变,在第二个errorFunc函数中对error的值也进行了改变。

因为这个promise对象是贯穿整个执行链条的,所以在第一个then()方法中对其值进行改变必然会反映到后面的then()方法中

一个异步模式的实例

Test3

第三个例子,我们创建了一个服务,然后在这个服务中创建了一个promise,服务的目的就是为了拉取github上面关于angularjs一些pull的数据,详细的代码可以看下面

下面的例子包含的部分有点多,因为我是在以前的例子上做的改动,大家可以只看promise这部分。

目录结构:

  • MyApp

    • js

      • app.js
      • controller.js
      • service.js
    • views
      • home.html
    • index.html

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

<code style="font-family: 'Source Code Pro', Consolas, Menlo, Monaco, 'Courier New', monospace; font-size: 1em; color: inherit; padding: 0px; white-space: inherit; background-image: none; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-tag" style="color: rgb(0, 102, 102);"><<span class="hljs-title" style="color: rgb(38, 139, 210);">h1</span>></span>{{name}}<span class="hljs-tag" style="color: rgb(0, 102, 102);"></<span class="hljs-title" style="color: rgb(38, 139, 210);">h1</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102);"><<span class="hljs-title" style="color: rgb(38, 139, 210);">h2</span>></span>Progress: {{progress}}<span class="hljs-tag" style="color: rgb(0, 102, 102);"></<span class="hljs-title" style="color: rgb(38, 139, 210);">h2</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102);"><<span class="hljs-title" style="color: rgb(38, 139, 210);">h3</span> <span class="hljs-attribute" style="color: rgb(181, 137, 0);">ng-show</span>=<span class="hljs-value" style="color: rgb(42, 161, 152);">"show"</span>></span>Please wait a moment...<span class="hljs-tag" style="color: rgb(0, 102, 102);"></<span class="hljs-title" style="color: rgb(38, 139, 210);">h3</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102);"><<span class="hljs-title" style="color: rgb(38, 139, 210);">p</span> <span class="hljs-attribute" style="color: rgb(181, 137, 0);">ng-repeat</span>=<span class="hljs-value" style="color: rgb(42, 161, 152);">"person in data"</span>></span>{{person.login}}<span class="hljs-tag" style="color: rgb(0, 102, 102);"></<span class="hljs-title" style="color: rgb(38, 139, 210);">p</span>></span>
</code>

index.html

<code style="font-family: 'Source Code Pro', Consolas, Menlo, Monaco, 'Courier New', monospace; font-size: 1em; color: inherit; padding: 0px; white-space: inherit; background-image: none; background-position: initial initial; background-repeat: initial initial;">
<span class="hljs-comment" style="color: rgb(147, 161, 161);"><!-- 不把下面的注释掉会出现问题,我是指上传到segmentfault上 --></span>
<span class="hljs-comment" style="color: rgb(147, 161, 161);"><!-- <head><meta charset="UTF-8"><title>Route</title><script src="http://cdn.bootcss.com/angular.js/1.4.0-rc.1/angular.js"></script><script src="../node_modules/angular-route/angular-route.js"></script><script src="js/app.js"></script><script src="js/controller.js"></script><script src="js/service.js"></script>
</head> --></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102);"><<span class="hljs-title" style="color: rgb(38, 139, 210);">body</span> <span class="hljs-attribute" style="color: rgb(181, 137, 0);">ng-app</span>=<span class="hljs-value" style="color: rgb(42, 161, 152);">"MyApp"</span>></span><span class="hljs-tag" style="color: rgb(0, 102, 102);"><<span class="hljs-title" style="color: rgb(38, 139, 210);">header</span>></span><span class="hljs-tag" style="color: rgb(0, 102, 102);"><<span class="hljs-title" style="color: rgb(38, 139, 210);">h1</span>></span>Header<span class="hljs-tag" style="color: rgb(0, 102, 102);"></<span class="hljs-title" style="color: rgb(38, 139, 210);">h1</span>></span><span class="hljs-tag" style="color: rgb(0, 102, 102);"><<span class="hljs-title" style="color: rgb(38, 139, 210);">hr</span>/></span><span class="hljs-tag" style="color: rgb(0, 102, 102);"></<span class="hljs-title" style="color: rgb(38, 139, 210);">header</span>></span><span class="hljs-tag" style="color: rgb(0, 102, 102);"><<span class="hljs-title" style="color: rgb(38, 139, 210);">div</span> <span class="hljs-attribute" style="color: rgb(181, 137, 0);">ng-view</span>></span><span class="hljs-tag" style="color: rgb(0, 102, 102);"></<span class="hljs-title" style="color: rgb(38, 139, 210);">div</span>></span><span class="hljs-tag" style="color: rgb(0, 102, 102);"><<span class="hljs-title" style="color: rgb(38, 139, 210);">footer</span>></span><span class="hljs-tag" style="color: rgb(0, 102, 102);"><<span class="hljs-title" style="color: rgb(38, 139, 210);">hr</span>/></span><span class="hljs-tag" style="color: rgb(0, 102, 102);"><<span class="hljs-title" style="color: rgb(38, 139, 210);">h1</span>></span>Footer<span class="hljs-tag" style="color: rgb(0, 102, 102);"></<span class="hljs-title" style="color: rgb(38, 139, 210);">h1</span>></span><span class="hljs-tag" style="color: rgb(0, 102, 102);"></<span class="hljs-title" style="color: rgb(38, 139, 210);">footer</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102);"></<span class="hljs-title" style="color: rgb(38, 139, 210);">body</span>></span></code>

AngularJS 的 $q 和 Promise相关推荐

  1. Angular的 $q, defer, promise,$http

    $q $q是Angular的一种内置服务,它可以使你异步地执行函数,并且当函数执行完成时它允许你使用函数的返回值(或异常). $q的其他方法 $q.when(value) //传递变量值,promis ...

  2. AngularJS学习之$q和promise介绍

    引用: ​下面我们通过讲解$q的API让你更多的了解promise异步编程模式.$q是做为angularjs的一个服务而存在的,只是对promise异步编程模式的一个简化实现版,源码中剔除注释实现代码 ...

  3. AngularJs中promise 和 $q 的一点解释

    以前只知道简单的ajax请求,也就是请求回调的模式,看了angularJs中大规模的promise, 尤其是$q 和defer , promise 以及怎么resolve,reject非常疑惑,在搜集 ...

  4. AngularJS $q 和 $q.all 单个数据源和多个数据源合并(promise的说明)

    这篇文章讲的不错, angular $q  和 promise!! -------------------------------------------------------------- 通过调 ...

  5. angular的$q服务和promise模式

    此承诺/延迟(promise/deferred)实现的灵感来自于 Kris Kowal's Q CommonJS Promise建议文档 将承诺(promise) 作为和 异步执行操作(action) ...

  6. $q -- AngularJS中的服务

    原文链接:  $q 官方文档 翻译时间: 2014年2月13日 翻译人员: 铁锚 描述 译者注: 看到了一篇非常好的文章,如果你有兴趣,可以查看: Promises与Javascript异步编程 , ...

  7. AngularJS学习笔记(一)

    前言 几个月之前了解过一点Angular,主要是通过phonecat应用程序了解一些入门东西,但是当被问及什么是Angular或者你对Angular的理解时,只记得一个MVVM双向数据绑定,显然这是不 ...

  8. 《AngularJS深度剖析与最佳实践》一2.10 承诺

    本节书摘来自华章出版社<AngularJS深度剖析与最佳实践>一书中的第2章,第2.10节,作者 雪狼 破狼 彭洪伟,更多章节内容可以访问云栖社区"华章计算机"公众号查 ...

  9. promise是什么?简单分析promise原理

    预备知识 回调函数 高级函数 发布-订阅模式 promise A+ 规范 promise是什么,能干什么 Promise是异步编程的一种解决方案,它可以解决异步回调地狱的问题,防止层层嵌套对程序代码带 ...

最新文章

  1. Observer Pattern 观察者模式
  2. 二叉树的基本应用知识总结
  3. 看我如何作死 | 将CPU、IO打爆
  4. ADMM:交替方向乘子算法
  5. 海量数据的分库分表技术演进,最佳实践
  6. 基于 VS 2010 阐述C# 4个特性
  7. 克里金插值c程序_C罗游艇晒太阳,坐下也有六块腹肌,乔治娜骄傲秀无名指上鸽子蛋...
  8. 初识设计模式之--简单工厂
  9. JAVA_WEB程序设计教程 pdf
  10. 分库分表中间件的高可用实践讲解
  11. 基础的数组/链表实现的队列
  12. 重载和重写的区别。。。。
  13. uedit上传视频时提示输入的视频地址有误,请检查后再试
  14. bm 37 bm38
  15. SCI (SSCI) 投稿全过程信件模板一览(Cover letter,催稿信,修改稿及回复,感谢信,询问校稿及校稿信) (转)
  16. Python小游戏之王者荣耀
  17. fighter(1.0)
  18. 人工智能学习-用apt卸载软件(7)
  19. 远程终端服务器连接(mstsc)步骤
  20. python金融数据缺失处理_顺利迈过Tushare+python3+mySql读取金融数据的坑

热门文章

  1. 嵌入式开发--RS-485通讯的问题
  2. 应用单源最短路径算法解决套利交易问题
  3. 计算机控制系统 阶段,一章 计算机控制系统概述.ppt
  4. 信号完整性(SI)电源完整性(PI)学习笔记(三)阻抗与电气模型
  5. 微信小程序在url简化_简化对Web应用程序的数据分析
  6. 序列预测中损失函数详解-MAE、MAPE、RMSE、Huber
  7. 《PostgreSQL开发指南》电子版PDF免费下载
  8. hdu 2204 容斥原理
  9. 在线教育网站数据分析——搭建指标体系
  10. 2021-2022学年广州市西关外国语学校九年级第一学期12月考英语试题