Promise.coroutine
支持Promise
作为可收缩价值类型。通过addYieldHandler(function handler)
,Promise.coroutine
也可以支持仅重新调整一次结果的任何类型。但是,我如何编写一个可以处理像co这样的generator
类型的yieldHandler呢?
答案 0 :(得分:26)
首先,Bluebird coroutines返回的承诺当然是可以自己屈服的:
var foo = Promise.coroutine(function*(){
yield Promise.delay(3000);
});
var bar = Promise.coroutine(function*(){
yield foo(); // you can do this.
});
通常,生成器是返回可迭代序列的函数的语法糖。在性质上没有任何异步。您可以编写在ES5甚至ES3中返回迭代的代码,并在生成器中将其与yield
一起使用。
现在 - 关于你的问题:
Promise.coroutine
。从您使用的特定迭代中产生任意迭代是容易出错的,将其包装在Promise.coroutine
中使它成为一个可以轻易产生的显式协程。这是明确的,清晰的,并保留了各种有用的属性。
让步承诺并非巧合,并且有充分理由认为ES7中的async
功能等待承诺。承诺代表了一种时间价值,它们确实是唯一有意义的东西 - 它们恰恰代表了 - 你等待的东西。出于这个原因 - 明确地等待承诺是有益的,并且可以实现可靠的抽象。
JavaScript中的生成器已经具有使用特殊符号构建的能力,不需要为特定的promise库添加特定的异常,以便从其他迭代中产生。
function genThreeToFour*(){
yield 3;
yield 4;
}
function genOneToFive*(){
yield 1;
yield 2;
yield * genThreeToFour(); // note the *, delegate to another sequence
yield 5;
}
从另一个序列产生的数据已经内置到生成器中,如果你想从另一个生成器中产生,你可以简单地yield *
调用它。这样就明确了你的授权。它只是代码中的另一个字符,但它更加明确,并且由于引擎知道委托,因此使用调试器也更容易。我还是更喜欢只承诺承诺,但如果你对此感到强烈的话 - 委托给其他发电机听起来比明确地产生发电机要好得多。
请注意,这也明显快于生成生成器,因为Promise.coroutine
的转换过程并不便宜,因为它意味着执行一次然后使用,因此转换本身不是&# 39; t fast但它产生一个非常快的函数(在几乎所有用例中都比async
快,并且比大多数人在大多数用例中编写callack的速度更快。如果你委托而不是每次都创建一个coroutine并运行它 - 你会有更好的表现。
addYieldHandler
很有可能这样做。如果您对速度惩罚和(在我看来更糟糕的情况下)抽象方面感到满意。您可以使用addYieldHandler
来生成生成器。
首先,"好"方式:
Promise.coroutine.addYieldHandler(function(gen) {
if (gen && gen.next && gen.next.call ){ // has a next which is a function
return Promise.try(function cont(a){
var n = gen.next(a);
if(n.done) return n.value; // `return` in generator
if(!n.value.then) return cont(n.value); // yield plain value
// handle promise case, propagate errors, and continue
return n.value.catch(gen.throw.bind(gen)).then(cont);
});
}
});
这里 - 我们添加了生成 iterables 而不是生成器的能力,其优点是不是生成器(例如 - 来自第三方库)但仍然生成可迭代的函数仍然可以产生。上面的用法类似于:yield generatorFn()
,您可以在其中调用生成器。请注意,我们的代码在这里复制Promise.coroutine
实际执行的操作,我们几乎最终得到了一个" native"实施它。
现在,如果您想要产生生成器,您仍然可以这样做:
var Gen = (function*(){}).constructor;
Promise.coroutine.addYieldHandler(function(gen) {
if (gen && (gen instanceof Gen)){ // detect explicit generator
return Promise.coroutine(gen)();
}
});
为了完整起见,但是:)