在前面的讨论中,我们展示了如何异步迭代生成器,这是一团乱麻似的回调在顺序性和合 理性方面的巨大进步。但我们错失了很重要的两点:Promise 的可信任性和可组合性()!
别担心,我们还会重获这些。ES6 中最完美的世界就是生成器(看似同步的异步代码)和 Promise(可信任可组合)的结合。
但如何实现呢?
里在运行 Ajax 例子中基于 Promise 的实现方法:
function foo(x,y) {
return request(
"http://some.url.1/?x=" + x + "&y=" + y
);
}
foo( 11, 31 )
.then(
function(text){
console.log( text );
},
function(err){
console.error( err );
}
);
在前面的运行 Ajax 例子的生成器代码中,foo(…) 没有返回值(undefined),并且我们的
迭代器控制代码并不关心 yield 出来的值。
而这里支持 Promise 的 foo(…) 在发出 Ajax 调用之后返回了一个 promise。这暗示我们可 以通过 foo(…) 构造一个 promise,然后通过生成器把它 yield 出来,然后迭代器控制代码 就可以接收到这个 promise 了。
但迭代器应该对这个 promise 做些什么呢?
它应该侦听这个 promise 的决议(完成或拒绝),然后要么使用完成消息恢复生成器运行,
要么向生成器抛出一个带有拒绝原因的错误。 我再重复一遍,因为这一点非常重要。获得 Promise 和生成器最大效用的最自然的方法就
是 yield 出来一个 Promise,然后通过这个 Promise 来控制生成器的迭代器。
让我们来试一下!首先,把支持 Promise 的 foo(…) 和生成器 *main() 放在一起:
function foo(x,y) {
return request(
"http://some.url.1/?x=" + x + "&y=" + y
);
}
function *main() {
try {
var text = yield foo( 11, 31 );
console.log( text );
}
catch (err) {
console.error( err );
} }
这次重构代码中最有力的发现是,*main() 之中的代码完全不需要改变!在生成器内部, 不管什么值 yield 出来,都只是一个透明的实现细节,所以我们甚至没有意识到其发生, 也不需要关心。
但现在如何运行 *main() 呢?还有一些实现细节需要补充,来实现接收和连接 yield 出来 的 promise,使它能够在决议之后恢复生成器。先从手工实现开始:
var it = main();
var p = it.next().value;
// 等待promise p决议 p.then(
function(text){
it.next( text );
},
function(err){
it.throw( err );
} );
实际上,这并没有那么令人痛苦,对吧?