- 创建 Future/Promise 对象
- 使用 Future 构造器
- 创建一个待定(pending)状态 promise 对象
- 创建一个成功(fulfilled)状态的 promise 对象
- 创建一个失败(rejected)状态的 promise 对象
- 使用 Future 上的工厂方法
- 创建一个成功(fulfilled)状态的 promise 对象
- 创建一个失败(rejected)状态的 promise 对象
- 同步创建一个 promise 对象
- 创建一个延迟 promise 对象
- 通过 Completer 来创建 promise 对象
- 通过 ECMAScript 6 方式来创建 promise 对象
- 通过 Future.promise 方法来创建 promise 对象
- 通过 hprose 上的方法来创建 promise 对象
- 使用 Future 构造器
- Future.prototype 上的基本方法
- then 方法
- done 方法
- catch 方法
- fail 方法
- catchError 方法
- resolve 方法
- reject 方法
- inspect 方法
- whenComplete 方法
- complete 方法
- always 方法
- fill 方法
创建 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 constructorafter Future constructorbefore Future.syncrunning Future.syncafter Future.syncrunning Future constructorpromise from Future.syncpromise 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 constructor1437889453871: after Future constructor1437889453872: before Future.delayed1437889453872: after Future.delayed1437889453873: running Future constructor1437889453873: promise from Future constructor1437889454173: running Future.delayed1437889454173: 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: falseisComplete: truehprose
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 方法的回调中发生异常,会直接抛出,并且无法被捕获。
因此,如果您不是在写单元测试,最好不要使用 done 方法。
catch 方法
该方法是 then(null, onRejected) 的简化写法。
具体使用方法可参见:MDN: Promise.prototype.catch()
fail 方法
该方法是 done(null, onRejected) 的简化方法。
如果您不是在写单元测试,最好不要使用 fail 方法。
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 completep2 completep3 completeresolve hprosereject thriftreject protobuf
complete 方法
该方法的回调函数 oncomplete 在不论成功还是失败的情况下都会执行,并且支持链式调用。相当于:then(oncomplete, oncomplete) 的简化写法。
该方法的最新版本支持不带参数调用,当不带参数调用时,返回一个新的 promise 对象,该对象会将源 promise 对象的失败(rejected)值转换为成功(fulfilled)值,这样在后面可以直接使用 then 的第一个回调参数统一处理。它的主要作用是当配合协程一起使用时,可以避免使用 try catch 来捕获异常。
always 方法
该方法的回调函数 oncomplete 在不论成功还是失败的情况下都会执行,但不支持链式调用。相当于:done(oncomplete, oncomplete) 的简化写法。
如果您不是在写单元测试,最好不要使用 always 方法。
fill 方法
将当前 promise 对象的值充填到参数所表示的 promise 对象中。
