此承诺/延迟(promise/deferred)实现的灵感来自于 Kris Kowal's Q CommonJS Promise建议文档 将承诺(promise) 作为和 异步执行操作(action)结果对象进行交互的接口,在指定的时间内可能完成也可能不能够完成(如超时,错误,拦截等等)。

从错误处理的角度看,延迟(deferred )和承诺(promise ) API 对于异步编程来说, 和同步编程的 try,catch, 以及throw 作用差不多.

  1. // 为了演示的目的,此处我们假设 `$q`, `scope` 以及 `okToGreet` 引用 在当前执行环境中可用
  2. // (比如他们已经被注入,或者被当做参数传进来了).
  3. function asyncGreet(name) {
  4. var deferred = $q.defer();
  5. setTimeout(function() {
  6. // 因为此function 在未来的事件循环中异步执行,
  7. // 我们需要把代码包装到到一个 $apply 调用中,以便正确的观察到 model 的改变
  8. scope.$apply(function() {
  9. deferred.notify('即将问候 ' + name + '.');
  10. if (okToGreet(name)) {
  11. deferred.resolve('你好, ' + name + '!');
  12. } else {
  13. deferred.reject('拒绝问候 ' + name + ' .');
  14. }
  15. });
  16. }, 1000);
  17. return deferred.promise;
  18. }
  19. var promise = asyncGreet('小漠漠');
  20. promise.then(function(greeting) {
  21. alert('成功: ' + greeting);
  22. }, function(reason) {
  23. alert('失败鸟: ' + reason);
  24. }, function(update) {
  25. alert('收到通知: ' + update);
  26. });

引人这种额外的复杂性的效果 在起初可能不明显。 在 promise 和 deferred APIs 进行承诺时好处就看出来了,请参考: https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md

延迟接口 | Deferred API

通过调用 $q.defer() 可以构建一个新的 deffered 实例。

deffered 对象的方法

  • resolve(value) ——传入 value 解决派生的 promise。 如果 value 是一个通过 $q.reject 构造的拒绝对象(rejection) , 该promise 将被拒绝。
  • reject(reason) ——拒绝派生的promise,并提供原因 。 这相当于通过 $q.reject构造的拒绝对象(rejection)作为参数传递给 resolve。
  • notify(value) ——在 promise 执行的过程中提供状态更新。 这在 promise 被解决或拒绝之前可能会被多次调用。

deffered 对象的属性

  • promise – {Promise} —— 与延迟(deferred)相关联的 promise 对象。

当创建 deferred 实例时会创建一个新的 promise 对象,并可以通过 deferred.promise 得到该引用。

promise 对象的目的是在 deferred 任务完成时,允许感兴趣的部分取得其执行结果。

promise 对象的方法

  • then(successCallback, errorCallback, notifyCallback) ——不管 promise 是被处理还是被拒绝, 一旦结果可用,then 就会尽快地异步调用 成功/错误 回调函数 只要结果是可用的。 调用回调函数时传递单个参数: 结果 或拒绝的理由。 此外,notify 回调可能被调用 0到多次,以提供 提供一个进度指示,之前承诺解决或拒绝。

    这个方法 返回一个新的promise 对象, 根据 successCallback , errorCallback的返回值进行解决或拒绝 。 它还通过 notifyCallback 方法的返回值进行通知。 promise 不能从notifyCallback方法得到解决或拒绝 。

  • catch(errorCallback) —— promise.then(null, errorCallback) 的快捷方式

  • finally(callback) ——让你可以观察到一个 promise 是被执行还是被拒绝, 但这样做不用修改最后的 value值。 这可以用来做一些释放资源或者清理无用对象的工作,不管promise 被拒绝还是解决。 更多的信息请参阅完整文档规范.

    因为在 ES3版本的JavaScript中 finally 是一个保留字关键字,不能作为属性名,为了适配 IE8,您需要使用 promise'finally' 这种形式来调用该方法。

promise 链

因为调用一个 promise 的 then 方法返回一个新的派生 promise实例,所以构建promises链也是很容易的:

  1. promiseB = promiseA.then(function(result) {
  2. return result + 1;
  3. });
  4. // promiseB 将会在处理完 promiseA 之后立刻被处理,
  5. // 并且其 value值是promiseA的结果增加1

我们可以创建任意长度的promise链;因为一个promise可以被另一个promises处理(进一步推迟解决完成时间),所以在promise链上的任意一点进行 暂停/推迟解决 都是可行的。 这使得实现功能强大的APIs 成为现实,例如 $http 的响应拦截器。

Kris Kowal's Q 与 $q 之间的区别

  • Angular中的$q 集成了 ng.$rootScope.Scope Scope模型观察机制,这意味着对models 的解决或拒绝速度将会更快,避免不必要的浏览器重绘(会导致UI闪烁)。
  • Q 比 $q拥有更多的功能特性,但带来的是代码字节数的增加。 $q 很轻量级,但包含了一般异步任务所需的所有重要功能。

    测试
  1. it('should simulate promise', inject(function($q, $rootScope) {
  2. var deferred = $q.defer();
  3. var promise = deferred.promise;
  4. var resolvedValue;
  5. promise.then(function(value) { resolvedValue = value; });
  6. expect(resolvedValue).toBeUndefined();
  7. // 模拟 promise 的 resolving
  8. deferred.resolve(123);
  9. // 注意 'then' function 不是同步调用的.
  10. // 因为我们想要 promise API 一直是异步的(async),
  11. // 不管是在同步调用还是异步调用中都是如此.
  12. expect(resolvedValue).toBeUndefined();
  13. // 使用 $apply()将 promise resolution 传递到 'then' functions .
  14. $rootScope.$apply();
  15. expect(resolvedValue).toEqual(123);
  16. }));

$q依赖$rootScope

$q的方法

  • all(promises)

    结合多个promises为单个promise,在所有输入的promise都处理之后,组合之后的promise才会处理完成。

    参数: promises

    类型: Array./Object.

    描述: promises的数组或者引用

    返回: Promise 返回单个的 promise,将与一个数组解决/散列值, 每个值对应于在相同的索引/关键的承诺 承诺 /散列数组。 如果任何承诺解决排斥,这产生的承诺将被拒绝 拒绝相同的值。

  • defer()

    创建一个 递延 对象代表一个将来完成任务。

    返回 Deferred 返回一个新实例的Deferred。

  • reject(reason)

    创建一个指定拒绝原因的promise. 此api应该用于在一个promises链中进行拒绝。 如果你正在处理promise 链中的最后一个promise,你不需要担心。

  1. promiseB = promiseA.then(function(result) {
  2. // success: 此处可以执行某些操作,然后直接使用原有的result,
  3. // 或者对result进行操作,来处理接下来的promiseB
  4. return result;
  5. }, function(reason) {
  6. // error: handle the error if possible and
  7. // resolve promiseB with newPromiseOrValue,
  8. // 否则转向拒绝 promiseB 的分支
  9. if (canHandle(reason)) {
  10. // 处理错误和恢复
  11. return newPromiseOrValue;
  12. }
  13. return $q.reject(reason);
  14. });

参数: reason

类型: *

描述: Constant, message, exception 或代表拒绝原因的 object。

返回: Promise 返回一个promise ,已经因为 reason 而被拒绝了 。

  • when(value)

    将一个对象(可能是value 或 [第三方]then-able promise) 包装为一个 $q promise。 这在你不确定所处理的对象是否是一个promise 时是很有用的,有可能该对象来自于一个不被信任的源头。

参数: value

类型: *

描述: promise 的值

返回 Promise 根据传入的值/或promise 返回一个包装后的 promise

angular的$q服务和promise模式的更多相关文章

  1. Angular通信$q服务和promise对象

    promise 约定(promise)是一个对象,表示在未来时间点会发生的某件事情,约定可以是三种状态之一:等待.完成或拒绝.约定将从等待状态开始,然后可以转换为完成或者拒绝状态,一旦约定完成或者被拒 ...

  2. Angular JS 学习笔记(自定义服务:factory,Promise 模式异步请求查询:$http,过滤器用法filter,指令:directive)

    刚学没多久,作了一个小项目APP,微信企业号开发与微信服务号的开发,使用的是AngularJS开发,目前项目1.0版本已经完结,但是项目纯粹为了赶工,并没有发挥AngularJS的最大作用,这几天项目 ...

  3. AngularJS 中的Promise --- $q服务详解

    先说说什么是Promise,什么是$q吧.Promise是一种异步处理模式,有很多的实现方式,比如著名的Kris Kwal's Q还有JQuery的Deffered. 什么是Promise 以前了解过 ...

  4. angular $q服务的用法

    Promise是一种和callback有类似功能却更强大的异步处理模式,有多种实现模式方式,比如著名的Q还有JQuery的Deffered. 什么是Promise 以前了解过Ajax的都能体会到回调的 ...

  5. $q服务——angular

    $q是做为angular的一个服务而存在的,只是对promise异步编程模式的一个简化实现版,源码中剔除注释实现代码也就二百多行,下面开始介绍$q的API. 一.defer对象(延迟对象)可以通$q. ...

  6. 浅谈Angular的 $q, defer, promise

    浅谈Angular的 $q, defer, promise 时间 2016-01-13 00:28:00  博客园-原创精华区 原文  http://www.cnblogs.com/big-snow/ ...

  7. angular的异步处理$q的使用(promise)

    Angular中的promise: Promise是一种异步方式处理值的方法.代表了一个函数最 终可能的返回值或者抛出的异常 在之前,通常都是使用闭包或者回调来响应非同步的有意义数据 使用promis ...

  8. angular中的$q服务实例

    用于理解$q服务 参考:http://www.zouyesheng.com/angular.html#toc39 广义回调管理 和其它框架一样, ng 提供了广义的异步回调管理的机制. $http 服 ...

  9. angular学习笔记(二十九)-$q服务

    angular中的$q是用来处理异步的(主要当然是http交互啦~). $q采用的是promise式的异步编程.什么是promise异步编程呢? 异步编程最重要的核心就是回调,因为有回调函数,所以才构 ...

随机推荐

  1. js——DOM操作(一)

    DOM:Document Object Model  文档对象模型 文档:html页面 文档对象:页面中元素 文档对象模型:定义  为了能够让程序(js)去操作页面中的元素 DOM会把文档看作是一棵树 ...

  2. Linux学习之服务器端口查看的方法

    1.用netstat查看: [grid@rac121 admin]$ netstat -anp | grep oracle (Not all processes could be identified ...

  3. QF——iOS中的数据库操作:SQLite数据库,第三方封装库FMDB,CoreData

    SQLite数据库: SQLite是轻量级的数据库,适合应用在移动设备和小型设备上,它的优点是轻量,可移植性强.但它的缺点是它的API是用C写的,不是面向对象的.整体来说,操作起来比较麻烦.所以,一般 ...

  4. Android Intent实现页面跳转

      Intent可以来协助完成Android各个组件之间的通信   1:startActivity(intent);     //直接启动                /*              ...

  5. Perfmon 介绍

    1.UI 1.笔图标,可以把视图里的细线加粗. 2.加号图标.可以为视图添加新的记数器. 3.操作-->属性.可以用于设置默认的采样时间. 2.增加计数据器页面 1.一个计数据器会包涵多个对象. ...

  6. sql CAST用法

    (1).CAST()函数的参数是一个表达式,它包括用AS关键字分隔的源值和目标数据类型.以下例子用于将文本字符串'12'转换为整型: ' AS int) (2).返回值是整型值12.如果试图将一个代表 ...

  7. C# 常用函数和方法集

    1.DateTime 数字型  System.DateTime currentTime=new System.DateTime(); 1.1 取当前年月日时分秒 currentTime=System. ...

  8. 2016 Multi-University Training Contest 2 总结

    第二次多校,出师未捷身先死 欣君看了一下09题,高呼水题,迅速码好,一A. 我看了11题,发现分奇偶讨论即可,于是按思路写好,一A. 欣君搞鼓出01题的一个公式,于是我照着写,一WA.简直不可思议,发 ...

  9. poj2390

    #include <stdio.h> #include <stdlib.h> int main() { int r,m,y,i; scanf("%d %d %d&qu ...

  10. iphone5升级到iOS7时出现“This device isn't eligible for the requested build”错误

    因为工作的需要我需要把自己的手机升级到iOS7,安装苹果的升级顺序总是报This device isn't eligible for the requested build错误,搜索相关的文章我的错误 ...