因为 Angular API 文档是全英文的,自己英语又这么渣,看了两行都看不下去了,只能自行翻译了(其实是自己汉字重新表达的)
原文传送门:Angular 学习之$q
简介
$q 是 AngularJS 内置的一种服务,可以让你在运行异步函数时使用函数运行完成后的返回值(或者是个异常)。
这是受Kris Kowal’s启发后,在 AngularJS 中实现的Promises/A+。
$q 可以以两种方式使用:
- 类似于 Kris Kowal’s Q 或者 jQuery’s Deferred
- 在某种程度上类似于 ES6 (ES2015) promises
$q constructor
ES6 流式风格的 promise 本质上是使用 $q 作为构造函数,并将 resolver
函数作为第一个参数传入构造函数。这和 ES6 中底层 Promise 的实现很相似,可以查看MDN。
尽管这种构造函数的方式在 AngularJS 是支持的,但这并不代表 ES6 Promise 的所有方法在 AngularJS 中都支持。
这种方式可以这么使用:
注意:ES6 风格的 progress/notify 回调接口目前 AngularJS 并不支持。
注意:不想 ES6 的实现,构造函数中抛出了异常并不会自动触发 reject 回调。
然而,传统的 CommonJS-style 用法在 AngularJS 中仍然是可用的,下面是它的文档。
The CommonJS Promise proposal将 promise 作为和一个对象交互的接口,它会返回一个异步动作的结果,在某一时刻该异步动作的结果有可能返回也有可能不返回。
从错误处理的角度来讲,deferred 和 promise APIs 是异步编程,而 try
, catch
和 throw
是同步编程。
首先,这种稍显复杂一点的编码方式的价值并不是很明显。promise 和 deferred APIs 带来的好处,可以参考:https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md。
另外,promise 可以让你整合传统的回调方法。如果想了解更多这方面信息,请参考Q documentation,特别是并行和串行添加 promises 这个章节。
The Deferred API
通过调用 $q.defer()
可以构造一个 deferred 实例。
deferred 对象的作用就是以 APIs 的形式暴露出关联的 Promise 实例,而 Promise 实例是可以用于检测异步动作是否执行成功,也可以查看异步任务的状态。
Methods
- resolve(value)-使用参数 value 解析出 promise。如果 value 是通过
$q.reject
构造的 rejection,promise 将会被 rejected 代替。 - rejected(reason)-使用参数 reason 拒绝 promise。这等价于使用 $q.reject 构造一个 rejection 来作为 resolve 的参数。
- notify(value)-在 promise 执行过程中提供更新状态码的功能。在 promise 解析或拒绝的过程中可以被调用多次。
Properties
- promise-{Promise}-这个 deferred 关联的 promise 对象。
The Promise API
创建了一个 deferred 实例后,通过调用 deferred.promise
就可以得到一个 promise 实例。
promise 对象的作用就是可以让对异步任务的结果感兴趣者能够访问异步 deferred 任务完成后的结果。
Methods
then(successCallback, [errorCallback], [notifyCallback])-无论 promise 什么时候执行了 resolved 或者 rejected,then 都会使用成功回调或者错误回调尽可能快的调用异步任务的结果。成功回调或者错误回调都只有一个参数:就是异步任务执行的结果或者 rejection 的原因。另外,在 promise resolved 或者 rejected 之前,notify 回调函数会被调用零次或者多次,用来提供其处理进度。这个方法会返回一个新的 promise,这个新的 promise 会通过返回
successCallback,
errorCallback来 resolved 或者 rejected(除非 value 是一个 promise,如果是那样的话,最终会通过 [promise chaining](http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promises-queues)执行)。通过
notifyCallback` 方法的返回值,它也会执行通知。promise 不能在 notifyCallback 方法中被 resolved 或者 rejected。当然了,errorCallback 和 notifyCallback 这两个参数是可选的。catch(errorCallback)-相当于
promise.then(null, errorCallback)` 的缩写- `finally(callback, notifyCallback)-允许你在不改变最终值的前提下检测到 promise 的执行或者 rejection。这对于不论 promise 被 rejected 还是 resolved,最终都需要释放资源或者做一些清理工作很有用。如果需要更多这方面的信息,可以参考full specification。
Chaining promises
因为调用 promise 的 then 方法会返回一个新的 promise,所以可以很容易的创建 promise 的链式调用:
我们可以创建任意长度的 promise 链式调用,因为一个 promise 可以使用其他的 promise resolved(这将会进一步推迟其解析过程),因此我们可以在链式调用的任意一点暂停或推迟 promise 的解析。$http’s 拦截器就是通过这种形式实现的。
Differences between Kris Kowal’s Q and $q
它们主要有两点不同:
- $q 被集成在 $rootScope.Scope 中,Scope 数据模型在 angular 中实现了观察者机制,这意味着可以在避免浏览器重绘 UI 的情况下更快的解析或者拒绝 promise。
- 相对 $q,Q有更多的特性,但是那也花费了一定的代价。$q 是包含了异步任务所需要的重要功能的最小实现。
Testing
|
|
Dependencies
Usage
$q(resolver);
Arguments
Param | Type | Details |
---|---|---|
resolver | function(function, function) | 对于新创建的 promise 来说,第一个参数 function 解析这个 promise,第二个参数 function 拒绝这个 promise |
Returns
Promise
新创建的 promise
Methods
- defer(): 创建一个代表着异步任务的 Deferred 对象,返回值就是这个 Deferred 实例
- reject(reason):创建一个使用指定 reason 拒绝的 promise。这个方法应该用在 promise 链接调用时拒绝一个 promise。如果你正在处理链式调用的最后一个 promise,那么你不必关心它。如果你把 deferreds/promises 和 catch/throw 做比较的话,你可以把 reject 当做 throw 关键字。这也相当于通过 promise 错误回调,你捕获了一个错误,并且你想要向前传递这个错误,所以你不得不 rethrow 这个错误通过 reject。1234567891011121314promiseB = promiseA.then(function(result) {// success: do something and resolve promiseB// with the old or a new resultreturn result;}, function(reason) {// error: handle the error if possible and// resolve promiseB with newPromiseOrValue,// otherwise forward the rejection to promiseBif (canHandle(reason)) {// handle the error and recoverreturn newPromiseOrValue;}return $q.reject(reason);});
reason 参数可以为任意类型:常量,消息,异常或者一个代表着拒绝原因的对象。返回值是一个使用 reason 拒绝的 promise。
- when(value, [successCallback], [errorCallback], [progressCallback]):将一个值或者第三方的 then-able promise 包装成 $q promise。当你处理一个有可能是 promise 也有可能不是 promise 的对象时,或者处理一个来自不受信任源的 promise 时,该方法比较有用。它的参数含义如下:
Param | Type | Details |
---|---|---|
value | * | Value or promise |
successCallback(optional) | Function= | |
errorCallback(optional) | Function= | |
progressCallback(optional) | Function= |
该方法返回值是一个传入参数转化后的 promise。
- resolve(value, [successCallback], [errorCallback], [progressCallback]):该方法是 ES6 语法中的
when
方法的别名,这里主要是为了维持命名一致性。它的参数含义如下:
Param | Type | Details |
---|---|---|
value | * | Value or promise |
successCallback(optional) | Function= | |
errorCallback(optional) | Function= | |
progressCallback(optional) | Function= |
该方法返回值也是一个 promise。
- all(promises):将多个 promises 结合为一个 promise,当所有的 promise 被解析后也就是这个结合体被解析。它的参数就是一个 promise 数组或以 promise 为值的 hash 映射对象。该方法返回值就是结合体 promise,所有 promise 都被解析时结合体 promise 才会被解析,只要有一个 promise 被拒绝,结合体 promise 就会被拒绝。
- race(promises):基本含义跟 all 方法相同,但是会结合体 promise 会尽可能快的被解析或者拒绝。
拓展学习
- 看完了这个文档,啥也没学会,还是看中文的好:Promise 对象
- 还是熟悉的汉字:jQuery的deferred对象详解
单词学习
- compliant,服从的,顺从的
- resemble,相似,类似于
- essentially ,本质上
- implicitly,含蓄地,暗中的
- expose,暴露,公开
- derived,推断出,衍生出
- fulfillment,执行,实行
- defer,推迟,服从
- flickering,闪烁
- consistency,一致性