概述
JavaScript 层层回调的异步编程让人望而生畏。而 Promise 的诞生就是为了解决这个问题,它提供了一种 Future 模式,大大简化了异步编程的复杂性。而 Promise/A+(中文版)是一个通用的、标准化的规范,它提供了一个可互操作的 then 方法的实现定义。Promise/A+ 规范的实现有很多,它们的共同点就是都有一个标准的 then
方法,而其它的 API 则各不相同。
ECMAScript 6 提供了一套 Promise
的标准实现,目前大部分浏览器和较新版本的 Node.js 也都已经支持,但老旧的浏览器和旧版本的 Node.js 上是没有内置 Promise
实现的。另外,ECMAScript 6 这套 Promise
实现,所提供的 API 也是极其有限,只能满足基本需求。
为了能够有一套统一的 Promise
实现,并且不依赖第三方库,hprose 自己实现了一套完全兼容 Promise/A+ 规范的 API。
hprose 2.0 之前的版本提供了一组 Future
/Completer
的 API,其中 Future
对象上也提供了 then
方法,但并不完全兼容 Promise/A+ 规范。它最初是参照 Dart 语言中的 Future
/Completer
设计的。
而在 hprose 2.0 版本中,我们对 Future
的实现做了比较大的改进,现在它既兼容 Dart 的 Future
/Completer
使用方式,又完全兼容 Promise/A+ 规范,而且还增加了许多非常实用的方法。下面我们就来对这些方法做一个全面的介绍。
创建 Future/Promise 对象
hprose 中提供了多种方法来创建 Future/Promise 对象。为了方便讲解,在后面我们不再详细区分 Future 对象和 Promise 对象实例的差别,统一称为 promise
对象。
使用 Future 构造器
创建一个待定(pending)状态 promise 对象
- var Future = hprose.Future;
- var promise = new Future();
该 promise
对象的结果尚未确定,可以在将来通过 resolve
方法来设定其成功值,或通过 reject
方法来设定其失败原因。
创建一个成功(fulfilled)状态的 promise 对象
- var Future = hprose.Future;
- var promise = new Future(function() { return 'hprose'; });
- promise.then(function(value) {
- console.log(value);
- });
该 promise
对象中已经包含了成功值,可以使用 then
方法来得到它。
创建一个失败(rejected)状态的 promise 对象
- var Future = hprose.Future;
- var promise = new Future(function() { throw 'hprose'; });
- promise.catch(function(reason) {
- console.log(reason);
- });
该 promise
对象中已经包含了失败值,可以使用 catch
方法来得到它。
使用 Future 上的工厂方法
Future
上提供了 6 个工厂方法,它们分别是:
- value
- resolve
- error
- reject
- sync
- delayed
其中value
和resolve
功能完全相同,error
和reject
功能完全相同。value
和error
这两个方法名来自 Dart 语言的Future
类。而resolve
和reject
这两个方法名则来自 ECMAScript 6 的 Promise 对象。因为最初是按照 Dart 语言的 API 设计的,因此,这里保留了value
和error
这两个方法名。
创建一个成功(fulfilled)状态的 promise 对象
- var Future = hprose.Future;
- var promise = Future.value('hprose'); // 换成 Future.resolve('hprose') 效果一样
- promise.then(function(value) {
- console.log(value);
- });
使用 value
或 resolve
来创建一个成功(fulfilled)状态的 promise
对象效果跟前面用 Future
构造器创建的效果一样,但是写起来更加简单,不再需要把结果放入一个函数中作为返回值返回了。
创建一个失败(rejected)状态的 promise 对象
- var Future = hprose.Future;
- var promise = Future.error('hprose'); // 换成 Future.reject('hprose') 效果一样
- promise.catch(function(reason) {
- console.log(reason);
- });
使用 error
或 reject
来创建一个失败(rejected)状态的 promise
对象效果跟前面用 Future
构造器创建的效果也一样,但是写起来也更加简单,不再需要把失败原因放入一个函数中作为异常抛出了。
同步创建一个 promise 对象
Future
上提供了一个:
- Future.sync(computation)
方法可以让我们同步的创建一个 promise
对象。
这里“同步”的意思是指 computation
的执行是同步执行的。而通过 Future
构造器创建 promise
对象时,computation
是异步执行的。为了可以更好地理解这一点,我们来看一个具体的例子:
- var Future = hprose.Future;
- function async() {
- console.log('before Future constructor');
- var promise = new Future(function() {
- console.log('running Future constructor');
- return 'promise from Future constructor';
- });
- promise.then(function(value) {
- console.log(value);
- });
- console.log('after Future constructor');
- }
- function sync() {
- console.log('before Future.sync');
- var promise = Future.sync(function() {
- console.log('running Future.sync');
- return 'promise from Future.sync';
- });
- promise.then(function(value) {
- console.log(value);
- });
- console.log('after Future.sync');
- }
- async();
- sync();
这个程序的执行结果是:
before Future constructor
after Future constructor
before Future.sync
running Future.sync
after Future.sync
running Future constructor
promise from Future.sync
promise from Future constructor
从这里我们可以看出,Future.sync
方法中的 computation
确实是同步执行的,而 Future
构造器中的 computation
也确实是异步执行的。但是对于 then
中回调的执行,却都是异步的。
仔细观察结果,你也许会发现另一个有趣的区别,这里就不再细说了,留给读者自己研究。
另外,前面所说的 Future.value
、Future.resolve
、Future.error
、Future.reject
这四个静态方法在创建 promise
对象时,跟使用 Future
构造器也存在同样的差别,但通常你可能不会注意到。
创建一个延迟 promise 对象
虽然通过 Future
构造器来创建一个 promise
对象跟使用 Future.sync
方法来比是异步的,但只是在执行顺序上能看出差别来,但是它并不会让你感到有明显的延时。如果你需要创建一个 promise
对象并且延迟一段时间后再执行 computation
函数,那么你可以使用
- Future.delayed(duration, value)
这个方法。
delayed
方法的第一个参数 duration
是一个毫秒值,第二个参数 value
既可以是一个 computation
函数,也可以是一个其它类型的值(包括 promise
对象)。当 value
不是函数时,相当于传入了一个:
- function() { return value; };
这样的 computation
函数。
这个 computation
函数会在延迟 duration
毫秒后执行,并将结果或失败原因充填入 promise
对象。
我们来看下面这个例子:
- var Future = hprose.Future;
- function normal() {
- console.log(Date.now() + ': before Future constructor');
- var promise = new Future(function() {
- console.log(Date.now() + ': running Future constructor');
- return "promise from Future constructor";
- });
- promise.then(function(value) {
- console.log(Date.now() + ': ' + value);
- });
- console.log(Date.now() + ': after Future constructor');
- }
- function delayed() {
- console.log(Date.now() + ': before Future.delayed');
- var promise = Future.delayed(300, function() {
- console.log(Date.now() + ': running Future.delayed');
- return "promise from Future.delayed";
- });
- promise.then(function(value) {
- console.log(Date.now() + ': ' + value);
- });
- console.log(Date.now() + ': after Future.delayed');
- }
- normal();
- delayed();
该程序的执行结果是:
1437889453869: before Future constructor
1437889453871: after Future constructor
1437889453872: before Future.delayed
1437889453872: after Future.delayed
1437889453873: running Future constructor
1437889453873: promise from Future constructor
1437889454173: running Future.delayed
1437889454173: promise from Future.delayed
这个结果一目了然,就不需要多做解释了。
通过 Completer 来创建 promise 对象
- var Completer = hprose.Completer;
- var completer = new Completer();
- var promise = completer.future;
- promise.then(function(value) {
- console.log(value);
- });
- console.log('isComplete: ' + completer.isCompleted);
- completer.complete('hprose')
- console.log('isComplete: ' + completer.isCompleted);
运行结果:
isComplete: false
isComplete: true
hprose
Future/Completer
这套 API 来自 Dart 语言,首先通过 Completer
构造器创建一个 completer
对象,然后这个 completer
对象上的 future
属性就是一个 promise
对象。通过 completer
的 complete
方法可以设置成功值。通过 completeError
方法可以设置失败原因。通过 isCompleted
属性,可以查看当前状态是否为已完成(在这里,成功(fulfilled)或失败(rejected)都算完成状态)。
在 hprose 2.0 之前的版本中,这是唯一可用的方法。但在 hprose 2.0 中,该方式已经被其他方式所代替。仅为兼容旧版本而保留。
通过 ECMAScript 6 方式来创建 promise 对象
hprose 提供了 ECMAScript 6 的 Promise
对象的兼容实现。
具体使用方式可以直接参见该文档:MDN: Promise
这里就不再重复了。
hprose-html5.js 里面已经自动创建了全局的 Promise
实现,如果检测已有内置实现或者其它第三方实现的话,将不会替换成 hprose 版本的。
使用该方式创建的 promise
对象,你应该只使用 ECMAScript 6 文档中记载的 API,而不能使用本文档中的大部分 API。因此,在使用 hprose 时,并不推荐使用此方式创建 promise
对象。
通过 Future.promise 方法来创建 promise 对象
该方法的参数跟 ECMAScript 6 的 Promise
构造器的参数相同,不同的是,使用该方法创建 promise
对象时,不需要使用 new
关键字。另外一点不同是,该方法创建的 promise
对象一定是 Future
的实例对象,而通过 Promise
构造器创建的 promise
对象可能会是内置或第三方的 Promise
实例对象。
因此,推荐使用该方法来代替 ECMAScript 6 的 Promise
构造器方式。
通过 hprose 上的方法来创建 promise 对象
Promises/A+ Compliance Test Suite 上提供了一套用于测试是否符合 Promises/A+ 规范的最小适配器接口。hprose 对象上已经实现了这套接口,即:
- hprose.resolved(value)
- hprose.rejected(reason)
- hprose.deferred()
- promise
- resolve(value)
- reject(reason)
当然,这套接口不仅仅可以用来测试。你也可以用于实际用途。
其中,hprose.resolved
方法跟 hprose.Future.value
、hprose.Future.resolve
功能相同。hprose.rejected
方法跟 hprose.Future.error
、hprose.Future.reject
功能相同。
而 hprose.deferred()
跟 new Completer()
的作用类似。其中 promise
属性跟 completer
的 future
属性作用相同。resolve
方法跟 completer
的 complete
方法作用相同。reject
方法跟 completer
的 completeError
方法作用相同。
这里也不再重复举例。
Future.prototype 上的基本方法
then 方法
then
方法是 Promise
的核心和精髓所在。它有两个参数:onFulfilled
, onRejected
。这两个参数皆为 function
类型。当它们不是 function
类型时,它们将会被忽略。当 promise
对象状态为待定(pending)时,这两个回调方法都不会执行,直到 promise
对象的状态变为成功(fulfilled)或失败(rejected)。当 promise
对象状态为成功(fulfilled)时,onFulfilled
函数会被回调,参数值为成功值。当 promise
对象状态为失败(rejected)时,onRejected
函数会被回调,参数值为失败原因。
then
方法的返回值是一个新的 promise
对象,它的值由 onFulfilled
或 onRejected
的返回值或抛出的异常来决定。如果onFulfilled
或 onRejected
在执行过程中没有抛出异常,那么新的 promise
对象的状态为成功(fulfilled),其值为 onFulfilled
或 onRejected
的返回值。如果这两个回调中抛出了异常,那么新的 promise
对象的状态将被设置为失败(rejected),抛出的异常作为新的 promise
对象的失败原因。
then
方法的 onFulfilled
, onRejected
这两个回调函数是异步执行的,即使当前的 promise
对象的状态为已完成(fulfilled 或 rejected)。
同一个 promise
对象的 then
方法可以被多次调用,其值不会因为调用 then
方法而改变。当 then
方法被多次调用时,所有的 onFulfilled
, onRejected
将按照原始的调用顺序被执行。
因为 then
方法的返回值还是一个 promise
对象,因此可以使用链式调用的方式实现异步编程串行化。
当 promise
的成功值被设置为另一个 promise
对象(为了区分,将其命名为 promise2
)时,then
方法中的两个回调函数得到的参数是 promise2
对象的最终展开值,而不是 promise2
对象本身。当 promise2
的最终展开值为成功值时,onFulfilled
函数会被调用,当 promise2
的最终展开值为失败原因时,onRejected
函数会被调用。
当 promise
的失败原因被设置为另一个 promise
对象时,该对象会直接作为失败原因传给 then
方法的 onRejected
回调函数。
then
方法是 Promise/A+ 规范的完整实现。
具体使用方法可参见:MDN: Promise.prototype.then()
done 方法
跟 then 方法类似,但 done 方法没有返回值,不支持链式调用,因此在 done 方法的回调函数中,通常不会返回值。如果在 done 方法的回调中发生异常,会直接抛出,并且无法被捕获。
catch 方法
该方法是 then(null, onRejected)
的简化写法。
具体使用方法可参见:MDN: Promise.prototype.catch()
fail 方法
该方法是 done(null, onRejected)
的简化方法。
catchError 方法
该方法是 catch
的增强版,它具有两个参数,第一个参数 onRejected
跟 catch
方法相同,第二个参数是一个测试函数。当该测试函数省略时,它的效果跟 catch
方法相同。例如:
- var Future = hprose.Future;
- var p = Future.reject(new TypeError('typeError'));
- p
- .catchError(function(reason) { return 'this is a syntax error'; },
- function(reason) { return reason instanceof SyntaxError; })
- .catchError(function(reason) { return 'this is a type error'; },
- function(reason) { return reason instanceof TypeError; })
- .then(function(value) { console.log(value); });
输出结果为:
this is a type error
resolve 方法
该方法可以将状态为待定(pending)的 promise
对象变为成功(fulfilled)状态。
该方法的参数值可以为任意类型。
该方法已绑定到它所在的 promise
对象,因此可以安全的作为回调函数进行传递。
reject 方法
该方法可以将状态为待定(pending)的 promise
对象变为失败(rejected)状态。
该方法的参数值可以为任意类型。
该方法已绑定到它所在的 promise
对象,因此可以安全的作为回调函数进行传递。
inspect 方法
该方法返回当前 promise
对象的状态。
如果当前状态为待定(pending),返回值为:
- { state: 'pending' }
如果当前状态为成功(fulfilled),返回值为:
- { state: 'fulfilled', value: value };
如果当前状态为失败(rejected),返回值为:
- { state: 'rejected', reason: reason };
whenComplete 方法
有时候,你不但想要在成功(fulfilled)时执行某段代码,而且在失败(rejected)时也想执行这段代码,那你可以使用 whenComplete
方法。该方法的参数为一个无参回调函数。该方法执行后会返回一个新的 promise
对象,除非在回调函数中抛出异常,否则返回的 promise
对象的值跟原 promise
对象的值相同。
- var Future = hprose.Future;
- var p1 = Future.resolve('resolve hprose');
- p1.whenComplete(function() { console.log('p1 complete'); })
- .then(function(value) { console.log(value); });
- var p2 = Future.reject('reject thrift');
- p2.whenComplete(function() { console.log('p2 complete'); })
- .catch(function(reason) { console.log(reason); });
- var p3 = Future.resolve('resolve protobuf');
- p3.whenComplete(function() { console.log('p3 complete');
- throw 'reject protobuf'; })
- .catch(function(reason) { console.log(reason); });
运行结果如下:
p1 complete
p2 complete
p3 complete
resolve hprose
reject thrift
reject protobuf
complete 方法
该方法的回调函数 oncomplete
在不论成功还是失败的情况下都会执行,并且支持链式调用。相当于:then(oncomplete, oncomplete)
的简化写法。
该方法的最新版本支持不带参数调用,当不带参数调用时,返回一个新的 promise 对象,该对象会将源 promise 对象的失败(rejected)值转换为成功(fulfilled)值,这样在后面可以直接使用 then
的第一个回调参数统一处理。它的主要作用是当配合协程一起使用时,可以避免使用 try
catch
来捕获异常。
always 方法
该方法的回调函数 oncomplete
在不论成功还是失败的情况下都会执行,但不支持链式调用。相当于:done(oncomplete, oncomplete)
的简化写法。
fill 方法
将当前 promise
对象的值充填到参数所表示的 promise
对象中。
Future 上的辅助方法
isFuture 方法
- Future.isFuture(obj)
用来判断是否是 Future
的实例对象。
isPromise 方法
- Future.isPromise(obj)
用来判断是否是 Future
或 ECMAScript 6 的 Promise
实例对象。
注意,该方法对其它符合 Promise/A+ 规范实现的 thenable
对象进行判断的返回值是 false
。
如果你需要一个 promise
对象,保险的做法是用 Future.value()
方法包装一下。
toPromise 方法
- Future.toPromise(obj)
如果 obj
是一个 Promise
对象,那么直接返回 obj
,否则返回 Future.value(obj)
。
all 方法
- Future.all(array)
该方法返回一个 promise
对象,该 promise
对象会在数组参数内的所有 promise
都被设置为成功(fulfilled)状态时,才被设置为成功(fulfilled)状态,其值为数组参数中所有 promise
对象的最终展开值组成的数组,其数组元素与原数组元素一一对应。
具体使用方法可参见:MDN: Promise.all()
Future.all
方法与 Promise.all
方法在参数上有一点区别,Future.all
方法的数组参数本身也可以是一个值为数组的 promise
对象。
race 方法
- Future.race(array)
该方法返回一个 promise
对象,这个 promise
在数组参数中的任意一个 promise
被设置为成功(fulfilled)或失败(rejected)后,立刻以相同的成功值被设置为成功(fulfilled)或以相同的失败原因被设置为失败(rejected)。
具体使用方法可参见:MDN: Promise.race()
Future.race
方法与 Promise.race
方法在参数上有一点区别,Future.race
方法的数组参数本身也可以是一个值为数组的 promise
对象。
join 方法
- Future.join([arg1[, arg2[, arg3...]]]);
该方法的功能同 all
方法类似,但它与 all
方法的参数不同,我们来举例看一下它们的差别:
- var Future = hprose.Future;
- var promise = Future.resolve(3);
- Future.all([true, promise])
- .then(function(values) {
- console.log(values);
- });
- Future.join(true, promise)
- .then(function(values) {
- console.log(values);
- });
输出结果如下:
[ true, 3 ]
[ true, 3 ]
any 方法
- Future.any(array)
该方法是 race
方法的改进版。
对于 race
方法,如果输入的数组为空,返回的 promise
对象将永远保持为待定(pending)状态。
而对于 any
方法,如果输入的数组为空,返回的 promise
对象将被设置为失败状态,失败原因是一个 RangeError
对象。
对于 race
方法,数组参数中的任意一个 promise
被设置为成功(fulfilled)或失败(rejected)后,返回的 promise
对象就会被设定为成功(fulfilled)或失败(rejected)状态。
而对于 any
方法,只有当数组参数中的所有 promise
被设置为失败状态时,返回的 promise
对象才会被设定为失败状态。否则,返回的 promise
对象被设置为第一个被设置为成功(fulfilled)状态的成功值。
settle 方法
- Future.settle(array)
该方法返回一个 promise
对象,该 promise
对象会在数组参数内的所有 promise
都被设置为成功(fulfilled)状态或失败(fulfilled)状态时,才被设置为成功(fulfilled)状态,其值为数组参数中所有 promise
对象的 inspect
方法返回值,其数组元素与原数组元素一一对应。
例如:
- var Future = hprose.Future;
- var p1 = Future.resolve(3);
- var p2 = Future.reject("x");
- Future.settle([true, p1, p2])
- .then(function(values) {
- console.log(values);
- });
输出结果为:
[ { state: 'fulfilled', value: true },
{ state: 'fulfilled', value: 3 },
{ state: 'rejected', reason: 'x' } ]
attempt 方法
- Future.attempt(handler[, arg1[, arg2[, arg3...]]]);
attempt
方法的作用是异步执行 handler
函数并返回一个包含执行结果的 promise
对象,handler
的参数分别为 arg1
, arg2
, arg3
…。参数可以是普通值,也可以是 promise
对象,如果是 promise
对象,则等待其变为成功(fulfilled)状态时再将其成功值代入 handler
函数。如果变为失败(rejected)状态,attempt
返回的 promise
对象被设置为该失败原因。如果参数中,有多个 promise
对象变为失败(rejected)状态,则第一个变为失败状态的 promise
对象的失败原因被设置为 attempt
返回的 promise
对象的失败原因。当参数中的 promise
对象都变为成功(fulfilled)状态时,handler
函数才会执行,如果在 handler
执行的过程中,抛出了异常,则该异常作为 attempt
返回的 promise
对象的失败原因。如果没有异常,则 handler
函数的返回值,作为 attempt
返回的 promise
对象的成功值。
- var Future = hprose.Future;
- function add(a, b) {
- return a + b;
- }
- var p1 = Future.resolve(3);
- Future.attempt(add, 2, p1)
- .then(function(value) {
- console.log(value);
- });
输出结果为:
5
run 方法
- Future.run(handler[, thisArg[, arg1[, arg2[, arg3...]]]]);
run
方法跟上面的 attempt
方法功能类似,唯一的区别是 run
方法的第二个参数为 thisArg
,他表示 handler
的执行上下文。当 thisArg
的值为 undefine
时,行为跟 attempt
方法完全一致。
例如:
- var Future = hprose.Future;
- function add(a, b) {
- return a + b;
- }
- var p1 = Future.resolve(3);
- Future.run(console.log, console, Future.attempt(add, 2, p1));
输出结果为:
5
wrap 方法
- Future.wrap(handler[, thisArg]);
wrap
方法返回一个包装好的函数,该函数的执行方式跟使用 Future.run
的效果一样。例如:
- var Future = hprose.Future;
- var add = Future.wrap(function(a, b) {
- return a + b;
- });
- var log = Future.wrap(console.log, console);
- var p1 = Future.resolve(3);
- log(add(2, p1));
输出结果为:
5
forEach 方法
- Future.forEach(array, callback[, thisArg])
该方法你可以认为是 Array.forEach
的 promise
版本,其中参数 array
可以是一个包含了 promise
元素的数组,也可以是一个包含了数组的 promise
对象。返回值是一个 promise
对象。如果参数数组中的 promise
对象为失败(rejected)状态,则该方法返回的 promise
对象被设置为失败(rejected)状态,且设为相同失败原因。如果在 callback
回调中抛出了异常,则该方法返回的 promise
对象也被设置为失败(rejected)状态,失败原因被设置为抛出的异常值。
- var Future = hprose.Future;
- function logArrayElements(element, index, array) {
- console.log('a[' + index + '] = ' + element);
- }
- // Note elision, there is no member at 2 so it isn't visited
- Future.forEach([2, Future.value(5), , 9], logArrayElements);
输出结果为:
a[0] = 2
a[1] = 5
a[3] = 9
every 方法
- Future.every(array, callback[, thisArg])
该方法你可以认为是 Array.every
的 promise
版本,其中参数 array
可以是一个包含了 promise
元素的数组,也可以是一个包含了数组的 promise
对象。返回值是一个 promise
对象。如果参数数组中的 promise
对象为失败(rejected)状态,则该方法返回的 promise
对象被设置为失败(rejected)状态,且设为相同失败原因。如果在 callback
回调中抛出了异常,则该方法返回的 promise
对象也被设置为失败(rejected)状态,失败原因被设置为抛出的异常值。
- var Future = hprose.Future;
- var log = Future.wrap(console.log, console);
- function isBigEnough(element, index, array) {
- return element >= 10;
- }
- var a1 = [12, Future.value(5), 8, Future.value(130), 44];
- var a2 = [12, Future.value(54), 18, Future.value(130), 44];
- var a3 = Future.value(a1);
- var a4 = Future.value(a2);
- log(Future.every(a1, isBigEnough)); // false
- log(Future.every(a2, isBigEnough)); // true
- log(Future.every(a3, isBigEnough)); // false
- log(Future.every(a4, isBigEnough)); // true
输出结果为:
false
true
false
true
some 方法
- Future.some(array, callback[, thisArg])
该方法你可以认为是 Array.some
的 promise
版本,其中参数 array
可以是一个包含了 promise
元素的数组,也可以是一个包含了数组的 promise
对象。返回值是一个 promise
对象。如果参数数组中的 promise
对象为失败(rejected)状态,则该方法返回的 promise
对象被设置为失败(rejected)状态,且设为相同失败原因。如果在 callback
回调中抛出了异常,则该方法返回的 promise
对象也被设置为失败(rejected)状态,失败原因被设置为抛出的异常值。
- var Future = hprose.Future;
- var log = Future.wrap(console.log, console);
- function isBiggerThan10(element, index, array) {
- return element > 10;
- }
- var a1 = [2, Future.value(5), 8, Future.value(1), 4];
- var a2 = [12, Future.value(5), 8, Future.value(1), 4];
- var a3 = Future.value(a1);
- var a4 = Future.value(a2);
- log(Future.some(a1, isBiggerThan10)); // false
- log(Future.some(a2, isBiggerThan10)); // true
- log(Future.some(a3, isBiggerThan10)); // false
- log(Future.some(a4, isBiggerThan10)); // true
输出结果为:
false
true
false
true
filter 方法
- Future.filter(array, callback[, thisArg])
该方法你可以认为是 Array.filter
的 promise
版本,其中参数 array
可以是一个包含了 promise
元素的数组,也可以是一个包含了数组的 promise
对象。返回值是一个 promise
对象。如果参数数组中的 promise
对象为失败(rejected)状态,则该方法返回的 promise
对象被设置为失败(rejected)状态,且设为相同失败原因。如果在 callback
回调中抛出了异常,则该方法返回的 promise
对象也被设置为失败(rejected)状态,失败原因被设置为抛出的异常值。
- var Future = hprose.Future;
- var log = Future.wrap(console.log, console);
- function isBigEnough(value) {
- return value >= 10;
- }
- var a1 = [12, Future.value(5), 8, Future.value(130), 44];
- var a2 = Future.value(a1);
- log(Future.filter(a1, isBigEnough));
- log(Future.filter(a2, isBigEnough));
输出结果为:
[ 12, 130, 44 ]
[ 12, 130, 44 ]
map 方法
- Future.map(array, callback[, thisArg])
该方法你可以认为是 Array.map
的 promise
版本,其中参数 array
可以是一个包含了 promise
元素的数组,也可以是一个包含了数组的 promise
对象。返回值是一个 promise
对象。如果参数数组中的 promise
对象为失败(rejected)状态,则该方法返回的 promise
对象被设置为失败(rejected)状态,且设为相同失败原因。如果在 callback
回调中抛出了异常,则该方法返回的 promise
对象也被设置为失败(rejected)状态,失败原因被设置为抛出的异常值。
- var Future = hprose.Future;
- var log = Future.wrap(console.log, console);
- var numbers = [1, Future.value(4), Future.value(9)];
- log(Future.map(numbers, Math.sqrt));
- log(Future.map(numbers, function(num) {
- return num * 2;
- }));
输出结果为:
[ 1, 2, 3 ]
[ 2, 8, 18 ]
reduce 方法
- Future.reduce(array, callback[, initialValue])
该方法你可以认为是 Array.reduce
的 promise
版本,其中参数 array
可以是一个包含了 promise
元素的数组,也可以是一个包含了数组的 promise
对象。返回值是一个 promise
对象。如果参数数组中的 promise
对象为失败(rejected)状态,则该方法返回的 promise
对象被设置为失败(rejected)状态,且设为相同失败原因。如果在 callback
回调中抛出了异常,则该方法返回的 promise
对象也被设置为失败(rejected)状态,失败原因被设置为抛出的异常值。
initialValue
的值也可以是一个 promise
对象。
- var Future = hprose.Future;
- var log = Future.wrap(console.log, console);
- var numbers = [Future.value(0), 1, Future.value(2), 3, Future.value(4)];
- function callback(previousValue, currentValue, index, array) {
- return previousValue + currentValue;
- }
- log(Future.reduce(numbers, callback));
- log(Future.reduce(numbers, callback, 10));
- log(Future.reduce(numbers, callback, Future.value(20)));
输出结果为:
10
20
30
reduceRight 方法
- Future.reduceRight(array, callback[, initialValue])
该方法你可以认为是 Array.reduceRight
的 promise
版本,其中参数 array
可以是一个包含了 promise
元素的数组,也可以是一个包含了数组的 promise
对象。返回值是一个 promise
对象。如果参数数组中的 promise
对象为失败(rejected)状态,则该方法返回的 promise
对象被设置为失败(rejected)状态,且设为相同失败原因。如果在 callback
回调中抛出了异常,则该方法返回的 promise
对象也被设置为失败(rejected)状态,失败原因被设置为抛出的异常值。
initialValue
的值也可以是一个 promise
对象。
- var Future = hprose.Future;
- var log = Future.wrap(console.log, console);
- function concat(a, b) {
- return a.concat(b);
- }
- var array = [[0, 1], Future.value([2, 3]), Future.value([4, 5])];
- log(Future.reduceRight(array, concat, []));
- log(Future.reduceRight(array, concat, Future.value([6, 7])));
输出结果为:
[ 4, 5, 2, 3, 0, 1 ]
[ 6, 7, 4, 5, 2, 3, 0, 1 ]
indexOf 方法
- Future.indexOf(array, searchElement[, fromIndex])
该方法你可以认为是 Array.indexOf
的 promise
版本,其中参数 array
可以是一个包含了 promise
元素的数组,也可以是一个包含了数组的 promise
对象。返回值是一个 promise
对象。如果参数数组中的 promise
对象为失败(rejected)状态,则该方法返回的 promise
对象被设置为失败(rejected)状态,且设为相同失败原因。
searchElement
的值也可以是一个 promise
对象。
- var Future = hprose.Future;
- var log = Future.wrap(console.log, console);
- var array = [1, Future.value(2), Future.value(3)];
- log(Future.indexOf(array, 2));
- log(Future.indexOf(array, Future.value(3), 1));
- log(Future.indexOf(array, 1, 1));
输出结果为:
1
2
-1
lastIndexOf 方法
- Future.lastIndexOf(array, searchElement[, fromIndex])
该方法你可以认为是 Array.lastIndexOf
的 promise
版本,其中参数 array
可以是一个包含了 promise
元素的数组,也可以是一个包含了数组的 promise
对象。返回值是一个 promise
对象。如果参数数组中的 promise
对象为失败(rejected)状态,则该方法返回的 promise
对象被设置为失败(rejected)状态,且设为相同失败原因。
searchElement
的值也可以是一个 promise
对象。
- var Future = hprose.Future;
- var log = Future.wrap(console.log, console);
- var array = [1, Future.value(2), Future.value(3)];
- log(Future.lastIndexOf(array, 2));
- log(Future.lastIndexOf(array, Future.value(3), 1));
- log(Future.lastIndexOf(array, 1, 1));
输出结果为:
1
-1
0
includes 方法
- Future.includes(array, searchElement[, fromIndex])
该方法你可以认为是 Array.includes
的 promise
版本,其中参数 array
可以是一个包含了 promise
元素的数组,也可以是一个包含了数组的 promise
对象。返回值是一个 promise
对象。如果参数数组中的 promise
对象为失败(rejected)状态,则该方法返回的 promise
对象被设置为失败(rejected)状态,且设为相同失败原因。
searchElement
的值也可以是一个 promise
对象。
- var Future = hprose.Future;
- var log = Future.wrap(console.log, console);
- var array = [1, Future.value(2), Future.value(3)];
- log(Future.includes(array, 2));
- log(Future.includes(array, Future.value(3), 1));
- log(Future.includes(array, 1, 1));
输出结果为:
true
true
false
find 方法
- Future.find(array, predicate[, thisArg])
该方法你可以认为是 Array.find
的 promise
版本,其中参数 array
可以是一个包含了 promise
元素的数组,也可以是一个包含了数组的 promise
对象。返回值是一个 promise
对象。如果参数数组中的 promise
对象为失败(rejected)状态,则该方法返回的 promise
对象被设置为失败(rejected)状态,且设为相同失败原因。predicate
是一个回调方法。
- var Future = hprose.Future;
- var log = Future.wrap(console.log, console);
- function isPrime(element, index, array) {
- var start = 2;
- while (start <= Math.sqrt(element)) {
- if (element % start++ < 1) {
- return false;
- }
- }
- return element > 1;
- }
- var array1 = [4, Future.value(6), 8, Future.value(12)];
- var array2 = [4, Future.value(5), 7, Future.value(12)];
- log(Future.find(array1, isPrime));
- log(Future.find(array2, isPrime));
输出结果为:
undefined
5
findIndex 方法
- Future.findIndex(array, predicate[, thisArg])
该方法你可以认为是 Array.findIndex
的 promise
版本,其中参数 array
可以是一个包含了 promise
元素的数组,也可以是一个包含了数组的 promise
对象。返回值是一个 promise
对象。如果参数数组中的 promise
对象为失败(rejected)状态,则该方法返回的 promise
对象被设置为失败(rejected)状态,且设为相同失败原因。predicate
是一个回调方法。
- var Future = hprose.Future;
- var log = Future.wrap(console.log, console);
- function isPrime(element, index, array) {
- var start = 2;
- while (start <= Math.sqrt(element)) {
- if (element % start++ < 1) {
- return false;
- }
- }
- return element > 1;
- }
- var array1 = [4, Future.value(6), 8, Future.value(12)];
- var array2 = [4, Future.value(5), 7, Future.value(12)];
- log(Future.findIndex(array1, isPrime));
- log(Future.findIndex(array2, isPrime));
输出结果为:
-1
1
Future.prototype 上的辅助方法
timeout 方法
- Future.prototype.timeout(duration[, reason])
创建一个新的 promise
对象,当超过设定的时间 duration
(单位毫秒),源 promise
对象如果还未被设置为成功(fulfilled)或失败(rejected),则新的 promise
对象被设置为一个 TimeoutError
或者自定义的 reason
。否则,其值跟源 promise
相同。
- var Future = hprose.Future;
- var add = Future.wrap(function(a, b) {
- return a + b;
- });
- var log = Future.wrap(console.log, console);
- var p1 = Future.delayed(200, 3).timeout(300);
- var p2 = Future.delayed(500, 3).timeout(300);
- log(add(p1, 2)).catch(log);
- log(add(p2, 5)).catch(log);
输出结果为:
5
{ [TimeoutError: timeout] message: 'timeout', name: 'TimeoutError' }
delay 方法
- Future.prototype.delay(duration)
创建一个新的 promise
对象,当经过 duration
毫秒后,该 promise
对象的值将被设置为跟源 promise
对象相同的成功值。如果源 promise
对象被设置为失败(rejected)状态,新的 promise
对象将立即被设为相同的失败原因,而无等待。
- var Future = hprose.Future;
- var add = Future.wrap(function(a, b) {
- return a + b;
- });
- var log = Future.wrap(console.log, console);
- var p = Future.value(3);
- var p1 = p.delay(200).timeout(300);
- var p2 = p.delay(500).timeout(300);
- log(add(p1, 2)).catch(log);
- log(add(p2, 5)).catch(log);
输出结果为:
5
{ [TimeoutError: timeout] message: 'timeout', name: 'TimeoutError' }
tap 方法
- Future.prototype.tap(onfulfilledSideEffect[, thisArg])
以下两种写法是等价的:
- promise.then(function(result) {
- onfulfilledSideEffect.call(thisArg, result);
- return result;
- });
- promise.tap(onfulfilledSideEffect, thisArg);
spread 方法
- Future.prototype.spread(onfulfilledArray[, thisArg])
以下两种写法是等价的:
- promise.then(function(array) {
- return onfulfilledArray.apply(thisArg, array);
- });
- promise.spread(onfulfilledArray, thisArg);
get 方法
- Future.prototype.get(key)
以下两种写法是等价的:
- promise.then(function(result) {
- return result[key];
- });
- promise.get(key);
set 方法
- Future.prototype.set(key, value)
以下两种写法是等价的:
- promise.then(function(result) {
- result[key] = value;
- return result;
- });
- promise.set(key, value);
下面我们来看一个例子:
- var Future = hprose.Future;
- function User() {
- this.name = "Tom";
- this.age = 18;
- }
- var log = Future.wrap(console.log, console);
- var p = Future.value(new User());
- p.get('name').then(function(result) { console.log(result); });
- log(p.get('age'));
- p.set('password', 'hprose')
- .tap(log)
- .tap(function(result) { console.log(result); })
- .set('password', 'I love hprose!')
- .get('password')
- .then(log);
输出结果:
Tom
{ name: 'Tom', age: 18, password: 'hprose' }
18
{ name: 'Tom', age: 18, password: 'I love hprose!' }
I love hprose!
注意上面的结果中,被 Future.wrap
包装过的 log
函数在执行时,并不是按照代码书写顺序执行的,也不是按照链式调用顺序执行的,它比在代码中书写的位置执行的要晚,因为被包装过的函数本身也是异步执行的,因此在输出结果上会比较反直觉。
比如上面输出结果中的这一句:
{ name: 'Tom', age: 18, password: 'I love hprose!' }
实际上是这一句代码:
- .tap(log)
输出的。
因此,在链式调用中使用 Future.wrap
包装过的函数,一定要注意这点。后面介绍的 bind
方法也同样需要注意这个问题。
apply 方法
- Future.prototype.apply(method[, args])
异步执行当前 promise
对象上的方法名为 method
的方法,参数为 args
数组中的元素,返回结果为包含了执行结果的 promise
对象。其中参数数组中的元素也可以为 promise
对象,在执行时,会带入这些 promise
对象所包含的成功值,如果这些 promise
对象中包含有失败状态的,则 method
方法不会执行,返回的 promise
对象中包含的失败原因为第一个变为失败(rejected)状态的参数的失败原因。
例如:
- var Future = hprose.Future;
- var log = Future.wrap(console.log, console);
- var p = Future.value([]);
- p.apply('push', ['banana', Future.value('apple'), 'peach'])
- .then(function(length) {
- console.log(length);
- log(p);
- });
- p.apply('push', ['banana', Future.error('apple'), 'peach'])
- .catch(function(reason) {
- console.log(reason);
- });
输出结果为:
apple
3
[ 'banana', 'apple', 'peach' ]
因为第二个 apply
的参数中包含有失败(rejected)状态的 promise
参数,因此第二个 apply
中的 push
方法并没有执行而提前返回,所以失败原因 apple
被先显示出来。
call 方法
- Future.prototype.call(method[, arg1[, arg2[, arg3...]]])
与上面的 apply
方法类似,唯一不同的是参数。看下面的例子:
- var Future = hprose.Future;
- var log = Future.wrap(console.log, console);
- var p = Future.value([]);
- p.call('push', 'banana', Future.value('apple'), 'peach')
- .then(function(length) {
- console.log(length);
- log(p);
- });
- p.call('push', 'banana', Future.error('apple'), 'peach')
- .catch(function(reason) {
- console.log(reason);
- });
执行结果与上面的 apply
的例子执行结果相同。
bind 方法
- Future.prototype.bind(method[, arg1[, arg2[, arg3...]]])
- Future.prototype.bind(methods[, arg1[, arg2[, arg3...]]])
bind
方法可以将当前 promise
对象所包含的成功值上的一个或多个方法及其参数绑定到当前的 promise
对象上。其中参数可以是 promise
对象,且绑定之后的方法在调用时也支持 promise
对象参数,返回值也为 promise
对象。例如:
- var Future = hprose.Future;
- var log = Future.wrap(console.log, console);
- var p = Future.value([]);
- p.bind('push');
- p.push('banana', Future.value('apple'), 'peach')
- .then(function(length) {
- console.log(length);
- log(p);
- });
- p.push('banana', Future.error('apple'), 'peach')
- .catch(function(reason) {
- console.log(reason);
- });
- var p2 = Future.value(new Date());
- p2.bind(Object.getOwnPropertyNames(Date.prototype));
- log(p2.toString());
- p2.setFullYear(1980).then(function() {
- log(p2.toString());
- });
运行结果如下:
apple
3
Tue Jul 28 2015 20:51:47 GMT+0800 (CST)
[ 'banana', 'apple', 'peach' ]
Mon Jul 28 1980 20:51:47 GMT+0800 (CST)
forEach 方法
- Future.prototype.forEach(callback[, thisArg])
该方法是 Array.prototype.forEach
的 promise
版本。它与 Array.prototype.forEach
的区别跟 Future.forEach
和 Array.forEach
的区别相同。
- var Future = hprose.Future;
- function logArrayElements(element, index, array) {
- console.log('a[' + index + '] = ' + element);
- }
- var p = Future.value([2, Future.value(5), , 9]);
- // Note elision, there is no member at 2 so it isn't visited
- p.forEach(logArrayElements);
输出结果为:
a[0] = 2
a[1] = 5
a[3] = 9
every 方法
- Future.prototype.every(callback[, thisArg])
该方法是 Array.prototype.every
的 promise
版本。它与 Array.prototype.every
的区别跟 Future.every
和 Array.every
的区别相同。
- var Future = hprose.Future;
- var log = Future.wrap(console.log, console);
- function isBigEnough(element, index, array) {
- return element >= 10;
- }
- var a1 = Future.value([12, Future.value(5), 8, Future.value(130), 44]);
- var a2 = Future.value([12, Future.value(54), 18, Future.value(130), 44]);
- var a3 = Future.value(a1);
- var a4 = Future.value(a2);
- log(a1.every(isBigEnough)); // false
- log(a2.every(isBigEnough)); // true
- log(a3.every(isBigEnough)); // false
- log(a4.every(isBigEnough)); // true
输出结果为:
false
true
false
true
some 方法
- Future.prototype.some(callback[, thisArg])
该方法是 Array.prototype.some
的 promise
版本。它与 Array.prototype.some
的区别跟 Future.some
和 Array.some
的区别相同。
- var Future = hprose.Future;
- var log = Future.wrap(console.log, console);
- function isBiggerThan10(element, index, array) {
- return element > 10;
- }
- var a1 = Future.value([2, Future.value(5), 8, Future.value(1), 4]);
- var a2 = Future.value([12, Future.value(5), 8, Future.value(1), 4]);
- var a3 = Future.value(a1);
- var a4 = Future.value(a2);
- log(a1.some(isBiggerThan10)); // false
- log(a2.some(isBiggerThan10)); // true
- log(a3.some(isBiggerThan10)); // false
- log(a4.some(isBiggerThan10)); // true
输出结果为:
false
true
false
true
filter 方法
- Future.prototype.filter(callback[, thisArg])
该方法是 Array.prototype.filter
的 promise
版本。它与 Array.prototype.filter
的区别跟 Future.filter
和 Array.filter
的区别相同。
- var Future = hprose.Future;
- var log = Future.wrap(console.log, console);
- function isBigEnough(value) {
- return value >= 10;
- }
- var p = Future.value([12, Future.value(5), 8, Future.value(130), 44]);
- log(p.filter(isBigEnough));
输出结果为:
[ 12, 130, 44 ]
map 方法
- Future.prototype.map(callback[, thisArg])
该方法是 Array.prototype.map
的 promise
版本。它与 Array.prototype.map
的区别跟 Future.map
和 Array.map
的区别相同。
- var Future = hprose.Future;
- var log = Future.wrap(console.log, console);
- var p = Future.value([1, Future.value(4), Future.value(9)]);
- log(p.map(Math.sqrt));
- log(p.map(function(num) {
- return num * 2;
- }));
输出结果为:
[ 1, 2, 3 ]
[ 2, 8, 18 ]
reduce 方法
- Future.prototype.reduce(callback[, initialValue])
该方法是 Array.prototype.reduce
的 promise
版本。它与 Array.prototype.reduce
的区别跟 Future.reduce
和 Array.reduce
的区别相同。
- var Future = hprose.Future;
- var log = Future.wrap(console.log, console);
- var p = Future.value([Future.value(0), 1, Future.value(2), 3, Future.value(4)]);
- function callback(previousValue, currentValue, index, array) {
- return previousValue + currentValue;
- }
- log(p.reduce(callback));
- log(p.reduce(callback, 10));
- log(p.reduce(callback, Future.value(20)));
输出结果为:
10
20
30
reduceRight 方法
- Future.prototype.reduceRight(callback[, initialValue])
该方法是 Array.prototype.reduceRight
的 promise
版本。它与 Array.prototype.reduceRight
的区别跟 Future.reduceRight
和 Array.reduceRight
的区别相同。
- var Future = hprose.Future;
- var log = Future.wrap(console.log, console);
- function concat(a, b) {
- return a.concat(b);
- }
- var p = Future.value([[0, 1], Future.value([2, 3]), Future.value([4, 5])]);
- log(p.reduceRight(concat, []));
- log(p.reduceRight(concat, Future.value([6, 7])));
输出结果为:
[ 4, 5, 2, 3, 0, 1 ]
[ 6, 7, 4, 5, 2, 3, 0, 1 ]
indexOf 方法
- Future.prototype.indexOf(searchElement[, fromIndex])
该方法是 Array.prototype.indexOf
的 promise
版本。它与 Array.prototype.indexOf
的区别跟 Future.indexOf
和 Array.indexOf
的区别相同。
- var Future = hprose.Future;
- var log = Future.wrap(console.log, console);
- var array = Future.value([1, Future.value(2), Future.value(3)]);
- log(array.indexOf(2));
- log(array.indexOf(Future.value(3), 1));
- log(array.indexOf(1, 1));
输出结果为:
1
2
-1
lastIndexOf 方法
- Future.prototype.lastIndexOf(searchElement[, fromIndex])
该方法是 Array.prototype.lastIndexOf
的 promise
版本。它与 Array.prototype.lastIndexOf
的区别跟 Future.lastIndexOf
和 Array.lastIndexOf
的区别相同。
- var Future = hprose.Future;
- var log = Future.wrap(console.log, console);
- var array = Future.value([1, Future.value(2), Future.value(3)]);
- log(array.lastIndexOf(2));
- log(array.lastIndexOf(Future.value(3), 1));
- log(array.lastIndexOf(1, 1));
输出结果为:
1
-1
0
includes 方法
- Future.prototype.includes(searchElement[, fromIndex])
该方法是 Array.prototype.includes
的 promise
版本。它与 Array.prototype.includes
的区别跟 Future.includes
和 Array.includes
的区别相同。
- var Future = hprose.Future;
- var log = Future.wrap(console.log, console);
- var array = Future.value([1, Future.value(2), Future.value(3)]);
- log(array.includes(2));
- log(array.includes(Future.value(3), 1));
- log(array.includes(1, 1));
输出结果为:
true
true
false
find 方法
- Future.prototype.find(predicate[, thisArg])
该方法是 Array.prototype.find
的 promise
版本。它与 Array.prototype.find
的区别跟 Future.find
和 Array.find
的区别相同。
- var Future = hprose.Future;
- var log = Future.wrap(console.log, console);
- function isPrime(element, index, array) {
- var start = 2;
- while (start <= Math.sqrt(element)) {
- if (element % start++ < 1) {
- return false;
- }
- }
- return element > 1;
- }
- var array1 = Future.value([4, Future.value(6), 8, Future.value(12)]);
- var array2 = Future.value([4, Future.value(5), 7, Future.value(12)]);
- log(array1.find(isPrime));
- log(array2.find(isPrime));
输出结果为:
undefined
5
findIndex 方法
- Future.prototype.findIndex(predicate[, thisArg])
该方法是 Array.prototype.findIndex
的 promise
版本。它与 Array.prototype.findIndex
的区别跟 Future.findIndex
和 Array.findIndex
的区别相同。
- var Future = hprose.Future;
- var log = Future.wrap(console.log, console);
- function isPrime(element, index, array) {
- var start = 2;
- while (start <= Math.sqrt(element)) {
- if (element % start++ < 1) {
- return false;
- }
- }
- return element > 1;
- }
- var array1 = Future.value([4, Future.value(6), 8, Future.value(12)]);
- var array2 = Future.value([4, Future.value(5), 7, Future.value(12)]);
- log(array1.findIndex(isPrime));
- log(array2.findIndex(isPrime));
输出结果为:
-1
1
原文: https://github.com/hprose/hprose-html5/wiki/Promise-%E5%BC%82%E6%AD%A5%E7%BC%96%E7%A8%8B