捕获JavaScript迭代器的返回值

5
考虑以下迭代器。它产生字符串 'foo' 和 'bar',然后返回 'quux' 作为返回值。我可以使用 Array.from 从迭代器中提取产出物,但如果我这样做,就没有办法读取返回值了。由于 Array.from 已经接收(并丢弃?)了返回值作为协议的一部分,因此返回值不再由迭代器返回。
const iterator = (function* () {
  yield 'foo'
  yield 'bar'
  return 'quux'
})()
const [foo, bar] = Array.from(iterator)
const quux = // ???

我能想到的唯一解决办法是编写一个间谍程序,监视迭代并将返回值作为副作用存储到预定义变量中,然后在Array.from丢弃返回值之前。是否有更好的访问返回值的替代方法?
let quux
const spy = function* (i) { /* extract return value from i and store it to quux */ }
const [foo, bar] = Array.from(spy(iterator))
2个回答

3
你说得对 - 当迭代器的next函数返回{ done: true, value: 'whatever' }时,该值会被静默丢弃。
正如你已经提到的,你可以编写一个包装函数(或类,如果你想要的话)。但是,你可以将它转换为常规迭代值,而不是保存到外部变量中。
例如:
function* yieldFinal (iterator) {
  let done, value
  do {
    ({ done, value } = iterator.next())
    yield value
  } while (!done)
}

const iterator = (function* () {
  yield 'foo'
  yield 'bar'
  return 'quux'
})()

const [foo, bar, quux] = Array.from(yieldFinal(iterator))

console.log(foo, bar, quux)

(注意:如果没有显式的返回值,那么最后一个值会得到undefined。)
但是,问题是,为什么你需要这样做?你可以写yield 'quux'; return而不必经过所有这些步骤,就可以实现相同的效果...

1
在 TypeScript 中,这是有区别的,因为 Generator<number, number, never> 保证始终至少包含一个数字,而 Generator<number, void, never> 可能不包含任何值。 - cyberixae
如果您感兴趣,这是我的代码。它有点乱,但它能完成工作。CherryDT的解决方案与我已经在做的非常接近。https://github.com/maasglobal/scrapql/blob/master/src/utils/non-empty-list.ts - cyberixae

-1
另一个解决方案:

function extractIterator<TItem, TResult>(iter: Generator<TItem, TResult>) {
    const items: TItem[] = [];
    let result: IteratorResult<TItem, TResult>;
    while ((result = iter.next())) {
        if (result.done) {
            return {
                items,
                result: result.value,
            };
        }
        items.push(result.value);
    }
    throw 'unreachable';
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接