为什么 yield 不能 resolve promise?

Why can yield not resolve promise?

我有以下代码:

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,returns 已定义 values。现在,valuesundefined。我认为 yield 可以解决像 async await 这样的承诺。

当您调用 .next 时,您会恢复 运行 生成器函数。如果你想用一个特定的值恢复它,你将一个值传递给 .next。因此,如果你想复制 redux-saga 解决承诺然后恢复生成器的行为,你需要接受第一次调用 .next 产生的承诺,等待承诺通过使用它的 [=14 来解决=] 方法,然后用它解析到的值调用 .next

const object = {
  getPastEvents: () => Promise.resolve([1,2,3])
}

function* fetchPastEvents() {
  console.log("entry")
  const values = yield object.getPastEvents()
  console.log(values)
}

const iterator = fetchPastEvents()
const promise = iterator.next().value;
promise.then(val => iterator.next(val))

我建议您不要自己这样做。如果这是你所说的传奇,那么 运行 通过 redux 传奇,你将免费获得这种行为。或者正如其他人所提到的,co 库实现了类似的功能。

I thought that yield can resolve a promise like async await.

不,yield 用于 yielding 一个 generator 函数 这意味着它会在该点停止函数执行, returns 右侧的表达式到 .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);
});

但我不知道这有什么用,特别是因为现在有专门针对该用例的异步生成器。

在生成器中使用 yield 并不能保证等到 promise 被完全填充。

为了使您的示例有效,您必须编写代码来调用实现可迭代协议的对象的 next 方法。

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 与此方法非常相似,它们都需要 promisified API。

但是要使用 Async & Await,请确保您的 JavaScript 引擎支持,否则您必须转译才能使它们在旧引擎中工作。

但是使用生成器将适用于大多数现代 JavaScript 引擎,它有点旧规范 (ES6)。

此外,通常转译 Async 和 Await 会生成大量代码,如果您想将内容保存得尽可能小,这可能会成为问题。

ES6 Generator 和 ES7 Async & Await 的主要区别是 ES6 Generator 不能使用 "Arrow function" 这在某些情况下非常关键(你必须在进入生成器之前在某处保存 "this" 引用函数的上下文),但是 ES7 异步函数可以做到这一点。

请注意,ES7 Async & Await 只是 promise 的语法糖 API,但 ES6 生成器不是。