我有以下代码:
object = {
getPastEvents: () => Promise.resolve([1,2,3])
}
function* fetchPastEvents() {
const values = yield object.getPastEvents()
console.log(values)
}
const events = fetchPastEvents()
events.next()
events.next()
现在,我想知道如何创建返回定义的getPastEvents
的函数values
。目前,values
是undefined
。我以为yield可以解决async await之类的承诺。
答案 0 :(得分:5)
调用.next
时,将继续运行生成器功能。如果要使用特定值恢复它,请将一个值传递到.next
中。因此,如果您想复制redux-saga解析诺言然后恢复生成器的行为,则需要采用第一次调用.next
所产生的诺言,等待诺言通过使用其{{1 }}方法,然后使用解析后的值调用.then
。
.next
我建议您不要自己这样做。如果这是您所说的传奇,请通过redux传奇运行它,您将免费获得此行为。或者像其他人提到的那样,co库实现了类似的功能。
答案 1 :(得分:3)
我认为yield可以解决async await之类的诺言。
否,yield
用于生成一个生成器函数,这意味着它会在此时停止函数执行,将右侧的表达式返回给.next()
的调用方,然后采用传递给下一个.next(value)
调用的值来继续执行。这是异步的,但与async
/ await
没有任何关系。但是,您可以产生一个承诺,并在该承诺解决时调用下一个.next(value)
:
async function co(generator) {
let iterator = generator();
let done, value;
do {
({ done, value } = iterator.next(await value);
} while(!done);
return value;
}
可用作:
co(function* doAsync() {
let result = yield somePromise();
console.log(result);
});
但是我不知道这怎么有用。
答案 2 :(得分:1)
在生成器中使用收益率并不能保证等到承诺被完全兑现。
要使您的示例可行,您必须编写代码以调用实现可迭代协议的对象的下一个方法。
function runGenerator(asyncGen) {
const gen = asyncGen();
let returnValue;
(function iterate(value){
returnValue = gen.next(value);
if(!returnValue.done) {
returnValue.value.then(iterate);
}
})();
}
const object = {
getPastEvents: () => Promise.resolve([1,2,3])
};
runGenerator(function*() {
const values = yield object.getPastEvents();
console.log(values);
});
请注意,这只是简单的实现,如果要使用实际项目,则必须检查更多条件。
我建议您使用co模块,而不是仅仅为此实现自己的模块。
请注意,Async&Await与这种方法非常相似,它们都需要有约定的API。
但是要使用Async&Await,请确保您的JavaScript引擎支持,否则您必须进行转换才能使其在较旧的引擎中运行。
但是使用生成器将可在大多数现代JavaScript引擎中使用,这是相当古老的规范(ES6)。
一般来说,转译Async&Await会产生大量代码,如果您想将内容的大小减小到最小,则可能是个问题。
ES6 Generator和ES7 Async&Await的主要区别在于ES6 Generator不能使用“箭头功能”,这在某些情况下确实很关键(但是在进入生成器功能的上下文之前,您必须将“ this”引用保存在某个地方), ES7异步功能可以做到这一点。
请注意,ES7 Async&Await只是Promise API的语法糖,但ES6生成器不是。