ECMA6发电机:产量承诺

时间:2015-05-22 16:16:56

标签: javascript node.js ecmascript-6

据我所知,ECMA6生成器应该能够屈服于一个返回promise的函数,最终返回已解析/拒绝的函数。使代码读取更像是同步代码,并避免回调地狱。

我正在使用node.js v0.12.2和--harmony以及以下代码。

var someAsyncThing = function() {
  return new Promise(function(resolve, reject) {
    resolve("I'm Resolved!");
  });
};

someAsyncThing().then(function(res) {console.log(res);});
// Works as expected: logs I'm Resolved!

function* getPromise() {
    var x = yield someAsyncThing();
    console.log("x: " + x); // Fails x undefined
}

var y = getPromise();
console.log(y); // returns {}

console.log(y.next());
// Fails: logs { value: {}, done: false }

我基于我在网上找到的几个例子中的代码。我做错了什么?

2 个答案:

答案 0 :(得分:3)

  

据我所知,ECMA6生成器应该能够屈服于一个返回一个promise的函数,最终返回已解决/拒绝的函数。

不,那不是他们的目的。 ES6生成器应该提供一种编写迭代器的简单方法 - 每次调用生成器函数都会产生一个迭代器。迭代器只是一个值序列 - 就像一个数组,但是动态消耗并且懒惰地生成。

现在,生成器可以被滥用用于异步控制流,方法是生成一系列异步消耗的promise,并使用每个等待的promise的结果推进迭代器。有关没有承诺的解释,请参阅here

所以你的代码缺少的是实际等待承诺并推进你的生成器的消费者。通常您使用专用库(如cotask.js),或许多承诺库提供的辅助函数之一(QBluebird,{ {3}},...),但为了这个答案的目的,我将展示一个简化的:

function run(gf) {
    let g = gf();
    return Promise.resolve(function step(v) {
         var res = g.next(v);
         if (res.done) return res.value;
         return res.value.then(step);
    }());
}

现在使用此功能,您可以实际执行"您的getPromise生成器:

run(getPromise).then(console.log, console.error);

答案 1 :(得分:2)

tl; dr:生成器产生的承诺必须向前移动发电机。

如果你看一下http://davidwalsh.name/async-generators中的第一个例子,你会注意到async函数实际上向前移动了迭代器:

function request(url) {
    // this is where we're hiding the asynchronicity,
    // away from the main code of our generator
    // `it.next(..)` is the generator's iterator-resume
    // call
    makeAjaxCall( url, function(response){
        it.next( response );               // <--- this is where the magic happens
    } );
    // Note: nothing returned here!
}

但是既然你正在处理承诺,我们可以稍微改进一下。 y.next().value返回一个承诺,你必须听取这个承诺。所以,不要写console.log(y.next()),而是写下:

var promise = y.next().value;
promise.then(y.next.bind(y)); // or promise.then(function(v) { y.next(v); });

Babel demo

当然这不太实用,因为现在你无法访问下一个产生的价值,而且你也不知道发电机何时完成。但是,您可以编写一个递归函数来处理它。这是runGenerator在本文后面介绍的内容。