蓝鸟协程使用

Bluebird coroutine usage

我正在尝试按如下方式使用 Bluebird 的协程:

var p = require('bluebird');
//this should return a promise resolved to value 'v'
var d = p.coroutine(function*(v) { yield p.resolve(v); });
//however this prints 'undefined'
d(1).then(function(v){ console.log(v); });

这里哪里不对?

引用 documentation of coroutine,

Returns a function that can use yield to yield promises. Control is returned back to the generator when the yielded promise settles.

因此,函数可以使用yield,但yield不用于return函数的值。无论您使用 return 语句从该函数中 returning 什么,都将是协程函数的实际解析值。

Promise.coroutine 只是让 yield 语句等待承诺解析,实际的 yield 表达式将被评估为已解析的值。

在你的例子中,表达式

yield p.resolve(v);

将被评估为 1,并且由于您没有明确地从函数中 returning 任何内容,因此默认情况下,JavaScript returns undefined。这就是为什么您得到 undefined 作为结果。


要解决这个问题,您实际上可以 return 产生的值,就像这样

var p = require('bluebird');

var d = p.coroutine(function* (v) {
    return yield p.resolve(v);
});

d(1).then(console.log);

让我们从您的代码开始:)

var d = p.coroutine(function*(v) { 
    yield p.resolve(v); 
});

当你执行 d(1) 时,bluebird 的协程会施展魔法并计算 promise 函数,即 p.resolve(v)。现在,协同程序的工作原理是调用 promise 函数,然后执行实际的 yield,即在执行 yielded promise 后,流程返回到实际的生成器。

现在 yield 不适用于 returning 值,不像 resolve 函数,后者可用于在承诺的情况下获取 'then' 中的值。

所以没有值被 returned,因此你得到未定义。

所以您可以做两件事:

首先简单地return明确的屈服值:

var d = p.coroutine(function* (v) {
    return p.resolve(v);
})

这将return在'yield'执行promise获得的值,因此可以使用'then'获得值。 喜欢

d(7).then((val) => {
    console.log(val);
});

但是,如果您有另一个 promise 函数要产生怎么办。即像这样的东西:

var d = bluebird.coroutine(function* (val) {
    yield bluebird.resolve(val);
    console.log('i am here');
    yield(bluebird.resolve('here' + val));
    console.log('i am at the last');
});

然后在此处执行 return 操作将不会执行另一个 yield 函数,即如果您 return 在上面代码中的第一个 yield 值处,那么第一个 yield 之后的代码将不会执行.

所以我能做的一件事就是处理给定承诺的 'then' 本身,例如:

var d = bluebird.coroutine(function* (val) {
    yield bluebird.resolve(val).then(function(data) {
        // process data here
        console.log(data);
    });
});

d(4).then(() => {
    console.log('done execution');
});

你可以用任何 no yielded promises 来做到这一点。 这是一个演示代码:

var bluebird = require('bluebird');
bluebird.coroutine(function *temp() {
    console.log('starting');
    yield(new Promise((resolve, reject) => { 
            setTimeout(function() {
                    return resolve('first yield data');
            }, 2000);
    }).then((data)=>{console.log(data)}));

    yield(new Promise((resolve, reject) => {
            setTimeout(function() {
                    resolve('second yield data');
            }, 3000);
    }).then((data) => {console.log(data)}));
})().then(() => {
         console.log('finally done');
     });

这样你就可以在 bluebird 中产生尽可能多的承诺,并在它们各自的 'then' 中获得它们解析的值并处理解析的数据。

function co(gen) {
    const it = gen(), next = it.next.bind(it), raise = it.throw.bind(it);
    return () => new Promise((resolve, reject) => {
        const factory = (fn) => (data) => {
            try {
                const {value, done} = fn(data);
                if (done) {
                    resolve(value);
                } else {
                    Promise.resolve(value).then(factory(next), factory(raise));
                }
            } catch(reason) {
                reject(reason);
            }
        };
        factory(next)();
    });
}

const example = co(function*() {
    // const x = yield Promise.reject(12);
    const x = yield Promise.resolve(12);
    return x
    // throw x
});

example(); // Promise {<resolved>: 12}