Promise.coroutine如何支持生成器作为可屈服值?

use*_*403 7 coroutine node.js promise bluebird

Promise.coroutine支持Promise作为可屈服值类型.并且通过addYieldHandler(function handler),Promise.coroutine也可以支持任何只重新调整一次的类型.但是我怎么能写一个可以处理generator类似co的类型的yieldHandler 呢?

Ben*_*aum 26

首先,Bluebird coroutines返回的承诺当然是可以自己屈服的:

var foo = Promise.coroutine(function*(){
    yield Promise.delay(3000);
});

var bar = Promise.coroutine(function*(){
    yield foo(); // you can do this.
});
Run Code Online (Sandbox Code Playgroud)

通常,生成器是用于返回可迭代序列的函数的语法糖.在性质上没有任何异步.您可以编写在ES5甚至ES3中返回迭代的代码,并yield在生成器中使用它.

现在 - 至于你的问题:

我不建议Promise.coroutine像这样使用.

从你正在使用的特定迭代中产生任意迭代是容易出错的,其中包装它Promise.coroutine使它成为一个你可以轻易产生的显式协程.这是明确的,清晰的,并保留了各种有用的属性.

屈服承诺并非偶然,并且有充分理由认为asyncES7 中的功能等待承诺.承诺代表了一种时间价值,它们确实是唯一有意义的东西 - 它们恰恰代表了 - 你等待的东西.出于这个原因 - 明确地等待承诺是有益的,并且可以实现可靠的抽象.

如果您确实希望从任意生成器中获取 - 您不需要通过Bluebird添加yield处理程序.

JavaScript中的生成器已经具有使用特殊表示法构建的能力,不需要为特定的promise库添加特定的异常,以便从其他迭代中产生.

function genThreeToFour*(){
    yield 3;
    yield 4;
}
function genOneToFive*(){
    yield 1;
    yield 2;
    yield * genThreeToFour(); // note the *, delegate to another sequence
    yield 5;
}
Run Code Online (Sandbox Code Playgroud)

从另一个序列中产生已经内置到生成器中,如果你想从另一个生成器中产生,你可以简单地yield *调用它.这样就明确了你的委托.它只是代码中的另一个字符,但它更明确,并且由于引擎知道委托,因此更容易使用调试器.我仍然更喜欢只承诺承诺,但如果你对此有强烈的感觉 - 委托给其他发电机听起来比明确地让发电机好.

请注意,这也比显式生成生成器快得多,因为转换过程Promise.coroutine并不便宜,因为它意味着执行一次然后使用,因此转换本身并不快但它产生的功能非常快(比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); 
        });
    }
});
Run Code Online (Sandbox Code Playgroud)

在这里 - 我们添加了产生迭代而不是生成器的能力,优点是不是生成器的函数(例如 - 来自第三方库)但仍然产生可迭代的函数仍然可以产生.上面的用法是这样的:yield generatorFn()你调用生成器的地方.请注意,我们的代码在这里复制了Promise.coroutine实际执行的操作,我们几乎最终得到了它的"本机"实现.

现在,如果你想产生生成器,你仍然可以这样做:

var Gen = (function*(){}).constructor;
Promise.coroutine.addYieldHandler(function(gen) {
    if (gen && (gen instanceof Gen)){ // detect explicit generator
        return Promise.coroutine(gen)();
    }
});
Run Code Online (Sandbox Code Playgroud)

这是为了完整,但:)