JS:如何在回调中使用生成器和yield

李岡諭*_*李岡諭 11 javascript yield callback

我使用JS生成器在回调中产生一个值setTimeout:

function* sleep() {
  // Using yield here is OK
  // yield 5; 
  setTimeout(function() {
    // Using yield here will throw error
    yield 5;
  }, 5000);
}

// sync
const sleepTime = sleep().next()
Run Code Online (Sandbox Code Playgroud)

为什么我不能在生成器的回调中产生值?

gue*_*314 13

function*声明是同步的.您可以产生一个新的Promise对象,链.then().next().value检索解决Promise价值

function* sleep() {
  yield new Promise(resolve => {
    setTimeout(() => {
      resolve(5);
    }, 5000);
  })
}

// sync
const sleepTime = sleep().next().value
  .then(n => console(n))
  .catch(e => console.error(e));
Run Code Online (Sandbox Code Playgroud)

  • 这只会解决一次,所以它不会产生太多 :) 例如,代码如何从`setInterval` 回调重复`yield`? (13认同)
  • 只产生一次的生成器有什么意义? (6认同)

Jac*_*cob 8

我来到这个问题寻找一种方法来将经常调用的回调(例如节点流、事件侦听器或setInterval回调)转换为异步可迭代,经过一些研究,我发现这个 NPM 包可以完成所有这些操作:EventIterator

EventIterator是一个小模块,可以极大地简化将事件发射器、事件目标和类似对象转换为 EcmaScript 异步迭代器的过程。它适用于浏览器和 Node.js 环境。

基本的setInterval可迭代:

import { EventIterator } from "event-iterator"
const counter = ms =>
  new EventIterator(({ push }) => {
    let count = 0
    const interval = setInterval(() => push(++count), ms)
    return () => clearInterval(interval)
  })

for await (const count of counter(1000)) console.log(count)
Run Code Online (Sandbox Code Playgroud)

(想push想像yield)。

虽然这在技术上并没有回答问题,但接受的答案也没有真正回答它,并且这个解决方案似乎非常接近OP正在寻找的内容。

  • 这应该是公认的答案。另一个完全没用,因为它只能产生一次。OTOH,我可以成功地使用 `EventIterator` 轻松创建迭代器。 (2认同)