【问题标题】:Why can yield not resolve promise?为什么yield不能解决promise?
【发布时间】:2019-03-25 17:08:07
【问题描述】:

我有以下代码:

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

【问题讨论】:

  • 为什么不使用const values = yield (await object.getPastEvents())
  • 假设 fetchPastEvents 是一个不能异步的 redux-saga。在我的用例中,我不在异步函数中。在任何情况下,您的建议都不会在我的示例中定义 values
  • 不,yield 关键字与 Promise 无关。它按原样产生价值。如果您正在寻找什么,为什么不直接使用async/await

标签: javascript ecmascript-6 yield


【解决方案1】:

当您调用.next 时,您会继续运行生成器函数。如果要使用特定值恢复它,请将值传递给.next。因此,如果你想复制 redux-saga 的解析承诺然后恢复生成器的行为,你需要将第一次调用产生的承诺带到 .next,等待承诺通过使用它的 .then 方法解决,然后使用解析为的值调用.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))

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

【讨论】:

    【解决方案2】:

    我认为 yield 可以解决像 async await 这样的承诺。

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

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

    【讨论】:

      【解决方案3】:

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

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

      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 不能使用“箭头函数”,这在某些情况下非常关键(在进入生成器函数的上下文之前,您必须在某处保存“this”引用),但是ES7 Async Function 可以做到这一点。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-03-30
        • 2015-07-18
        相关资源
        最近更新 更多