如何从收益中获得回报*

时间:2020-01-03 09:59:58

标签: javascript async-await generator

有什么办法可以从yield * asyncIterator返回吗?

背景

给出这样的异步迭代器:

const asyncIterator = {
  next () {
    return new Promise(resolve => setTimeout(() => resolve('next'), 500))
  },
  return () {
    return Promise.resolve('return')
  },
  [Symbol.asyncIterator] () {
    return this
  }
}

以下内容将永远不会调用其return方法:

async * yieldFromIterator () {
  yield 'start'
  yield * asyncIterator
}

const yieldingIterator = yieldFromIterator()
console.log(await yieldingIterator.next()) // 'start'
console.log(await yieldingIterator.next()) // 'next'
console.log(await yieldingIterator.return()) // never resolved

这也不是:

async * yieldFromIterator () {
  yield 'start'
  for await (const result of asyncIterator) {
    yield result
  }
}

const yieldingIterator = yieldFromIterator()
console.log(await yieldingIterator.next()) // 'start'
console.log(await yieldingIterator.next()) // 'next'
console.log(await yieldingIterator.return()) // never resolved

当然可以做到以下几点:

async * returnIterator () {
  yield 'start'
  return asyncIterator
}

const returningIterator = returnIterator()
console.log(await returningIterator.next()) // 'start'
console.log(await returningIterator.next()) // 'next'
console.log(await returningIterator.return()) // 'return'

非常感谢:)

1 个答案:

答案 0 :(得分:4)

您的asyncIterator有一个错误:承诺must be a result object的实现值(实现IteratorResult interface的对象,其形状为{done, value})。但是,您将使用字符串来实现诺言。

如果将其更新为返回结果对象,则会看到返回:

const asyncIterator = {
  next () {
    return new Promise(resolve => setTimeout(() => resolve({value: 'next', done: false}), 500))
  },
  return () {
    return Promise.resolve({value: 'return', done: true})
  },
  [Symbol.asyncIterator] () {
    return this
  }
}

async function * yieldFromIterator () {
  yield 'start'
  yield * asyncIterator
}

(async function() {
  const yieldingIterator = yieldFromIterator()
  console.log(await yieldingIterator.next())   // {value: 'start', done: false}
  console.log(await yieldingIterator.next())   // {value: 'next', done: false}
  console.log(await yieldingIterator.return()) // {value: 'return', done: true}
})().catch(error => {
  console.error(error)
})
.as-console-wrapper {
    max-height: 100% !important;
}


另外,asyncIterator还有另一个问题(不一定是错误):它不继承自%AsyncIteratorPrototype%及其下面的链。从理论上讲,代码可以将方法添加到%AsyncIteratorPrototype%,%IteratorPrototype%等中,而asyncIterator中将缺少这些方法。

通常,异步生成器函数是创建异步迭代器对象的最佳方法(因为异步生成器是异步迭代器),就像非异步生成器函数是创建迭代器的最佳方法一样。您将获得yield语法并从标准原型继承的好处。

也就是说,如果您使用异步生成器函数实现了asyncIterator,您将不会看到'return'字符串来响应该return调用。您需要致电next,并在return中使用yieldFromIterator

const delay = (ms, ...args) => new Promise(resolve => setTimeout(resolve, ms, ...args));

const asyncIterator = (async function*() {
  await delay(500);
  yield 'next';
  return 'return';
})();

async function * yieldFromIterator () {
  yield 'start'
  return yield * asyncIterator // <=== Added `return`
}

(async function() {
  const yieldingIterator = yieldFromIterator()
  console.log(await yieldingIterator.next()) // {value: 'start', done: false}
  console.log(await yieldingIterator.next()) // {value: 'next', done: false}
  console.log(await yieldingIterator.next()) // {value: 'return', done: true}
  // Changed to `next` −−−−−−−−−−−−−−^
})().catch(error => {
  console.error(error)
})
.as-console-wrapper {
    max-height: 100% !important;
}

相关问题