您的位置:首页 > Web前端 > AngularJS

$q in Angular [ngdoc service] 翻译

2017-05-08 19:02 344 查看
[TOC]

promise / deferred
实现的灵感来自于 [Kris Kowal's Q][1] - [The CommonJS Promise proposal][2] (CommonJS Promise建议文档)描述了将
promise
作为一个接口,用来与异步执行操作
(action)
的结果对象
进行交互,该操作
(action)
在给定时间内可能或不可能完成(如超时,错误,拦截等等)。

从错误处理的角度看,
deferred
promise
APIs 对于异步编程, 等同于同步编程的
try
catch
以及
throw
关键字.

// 在本例中,假设 `$q`, `scope` 以及 `okToGreet` 在当前执行环境中是可用的
// (如它们已经被注入,或者作为参数传递进来).
function asyncGreet(name) {
var deferred = $q.defer();
setTimeout(function () {
deferred.notify('About to greet ' + name + '.');
if (okToGreet(name)) {
deferred.resolve('Hello, ' + name + '!');
} else {
deferred.reject('Greeting ' + name + ' is not allowed.');
}
}, 1000);
return deferred.promise;
}
var promise = asyncGreet('Robin Hood');
promise.then(function (greeting) {
alert('Success: ' + greeting);
}, function (reason) {
alert('Failed: ' + reason);
}, function (update) {
alert('Got notification: ' + update);
});

一开始,引人这种额外的复杂性,其效果可能是不明显的。 当执行顺序按照
promise
deferred
APIs 确定的那样,其优点就显现出来了。请参考: [https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md][3]

另外
promise api
可以实现在传统的回调([CPS][4])方法中难以实现的组合方式。 更多信息请查阅 [Q文档][5] ,尤其是 [串行与并行结合promises][6] 的章节。

Deferred API

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

deffered
对象是将
Promise
实例与 可以用来标记任务状态(执行是否成功)的 APIs 相关联。

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
对象。

Promise API

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

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

promise 对象的方法

then(successCallback, errorCallback, notifyCallback)
—— 不管
promise
是被处理还是被拒绝, 一旦结果(the result)可用,
then
就会尽快地异步调用. 回调函数被调用时会传递进一个参数: 结果(the result)或者拒绝的理由(reject reason)。此外,在
promise
被 reslove 或 reject 之前,
notify
回调可能被调用
0
到多次,以提供一个进度的指示。

这个方法会返回一个新的
promise
对象,该对象根据
successCallback
errorCallback
的返回值表示是被 resolved 或 rejected 。 它还通过
notifyCallback
方法的返回值进行通知。
promise
不能从
notifyCallback
方法得知是被 resloved 还是 rejected.

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

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

因为在 ES3 版本的 JavaScript 中
finally
是一个保留字,不能作为属性名,所以为了兼容 IE8 与 Andriod 2.x, 需要借助
promise['finally'](callback)
这种形式来调用该方法。

Chaining promises | 创建promise链

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

promiseB = promiseA.then(function(result) {
return result + 1;
});

// promiseB 将会在处理完 promiseA 之后立即被处理,
// 并且其 value 值是 promiseA 的结果增加 1

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

Kris Kowal's Q 与 \(q 之间的区别 主要区别有两点: Angular中的 `\)q
集成了 {@link ng.$rootScope.Scope}
Scope
模型观察机制,这意味着解决或拒绝的结果会以更快地传播速度反映在数据模型中(model),避免不必要的浏览器重绘,因为重绘会导致UI闪烁.
Q
\(q` 拥有更多的功能特性,但也带来了代码字节数的增加。`\)q` 虽然是轻量级的,但包含了一般的异步任务所需的所有重要功能。

it('should simulate promise', inject(function($q, $rootScope) {
var deferred = $q.defer();
var promise = deferred.promise;
var resolvedValue;

promise.then(function(value) { resolvedValue = value; });
expect(resolvedValue).toBeUndefined();

// 模拟 promise 的 resolving
deferred.resolve(123);
// 注意 'then' function 不是同步调用的.
// 因为我们需要 promise API 一直是异步的(async),
// 不管是在同步调用还是异步调用中都是如此.
expect(resolvedValue).toBeUndefined();

// 使用 $apply()将 promise resolution 传递到 'then' functions .
$rootScope.$apply();
expect(resolvedValue).toEqual(123);
}));

Dependencies

$rootScope

Methods

$q# defer()

创建一个
递延(Deferred)对象
表示一个将来要完成任务.

返回 {Deferred} 返回一个新实例的
Deferred
.

$q# reject(reason)

创建一个被特定的原因 rejected 的
promise
. 此 api 应该用于在一个
promises链
中进行转发(?) rejection。如果你正在处理
promise链
中的最后一个
promise
,你就不用担心它。

deferreds/promises
与我们熟悉的的
try/catch/throw
行为进行对比,可以认为
reject
相当于 JavaScript 中的
throw
关键字。这也意味着如果你通过一个
promise
error
回调,
"catch"
了一个错误,而且你想要从当前的
promise
中转发这个
error
到派生的
promise
中,就必须通过返回的
rejection
(由 reject 构造的),重新抛出(rethrow)这个
error


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

参数: reason

类型: *

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

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

when(value)

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

参数: value

类型: *

描述: promise 的值

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

all(promises)

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

参数: promises

类型: Array.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: