比如,这可能是一个更简洁的方案:
// 注:普通函数,不是生成器 function bar(url1,url2) { return Promise.all( [
request( url1 ),
request( url2 )
] );
}
function *foo() {
// 隐藏bar(..)内部基于Promise的并发细节 var results = yield bar(
"http://some.url.1",
"http://some.url.2"
);
var r1 = results[0];
var r2 = results[1];
var r3 = yield request(
"http://some.url.3/?v=" + r1 + "," + r2
);
console.log( r3 );
}
// 使用前面定义的工具run(..) run( foo );
在 *foo() 内部,我们所做的一切就是要求 bar(…) 给我们一些 results,并通过 yield 来等待结果,这样更简洁也更清晰。我们不需要关心在底层是用Promise.all([ … ]) Promise 组合来实现这一切。
我们把异步,实际上是 Promise,作为一个实现细节看待。 如果想要实现一系列高级流程控制的话,那么非常有用的做法是:把你的 Promise 逻辑隐
藏在一个只从生成器代码中调用的函数内部。比如:
function bar() {
Promise.all( [
baz( .. )
.then( .. ),
Promise.race( [ .. ] )
])
.then( .. ) }
有时候会需要这种逻辑,而如果把它直接放在生成器内部的话,那你就失去了几乎所有一 开始使用生成器的理由。应该有意将这样的细节从生成器代码中抽象出来,以避免它把高 层次的任务表达变得杂乱。
创建代码除了要实现功能和保持性能之外,你还应该尽可能使代码易于理解和维护。
对编程来说,抽象并不总是好事,很多时候它会增加复杂度以换取简洁性。 但是在这个例子里对生成器 +Promise 异步代码来说,相比于其他 实现,这种抽象更加健康。尽管如此,还是建议大家要注意具体情况具体分 析,为你和你的团队作出正确的决定。