gpt4 book ai didi

javascript - 如何确定 javascript 迭代器是否提前终止?

转载 作者:行者123 更新时间:2023-11-30 11:30:30 25 4
gpt4 key购买 nike

假设我有一个生成器:

function* source() {
yield "hello"; yield "world";
}

我创建可迭代对象,使用 for 循环进行迭代,然后在迭代器完全完成(返回完成)之前跳出循环。

function run() {
for (let item of source()) {
console.log(item);
break;
}
}

问题:我如何从可迭代端发现迭代器提前终止?

如果您尝试直接在生成器本身中执行此操作,似乎没有任何反馈:

function* source2() {
try {
let result = yield "hello";
console.log("foo");
} catch (err) {
console.log("bar");
}
}

...“foo”和“bar”都没有被记录。

最佳答案

编辑:请参阅较新的已接受答案。我会保留它,因为它确实/确实有效,当时我很高兴能够破解一个解决方案。但是,正如您在已接受的答案中看到的那样,最终的解决方案非常简单,现在已经确定。

我注意到 typescript 将 Iterator (lib.es2015) 定义为:

interface Iterator<T> {
next(value?: any): IteratorResult<T>;
return?(value?: any): IteratorResult<T>;
throw?(e?: any): IteratorResult<T>;
}

我拦截了这些方法并记录了调用,它确实显示如果迭代器提前终止——至少通过 for-loop——然后​​ return 方法叫做。 如果消费者抛出错误,它也会被调用。如果允许循环完全迭代迭代器 return 被调用。

返回 hack

因此,我进行了一些修改以允许捕获另一个 可迭代对象 - 因此我不必重新实现迭代器。

function terminated(iterable, cb) {
return {
[Symbol.iterator]() {
const it = iterable[Symbol.iterator]();
it.return = function (value) {
cb(value);
return { done: true, value: undefined };
}
return it;
}
}
}

function* source() {
yield "hello"; yield "world";
}

function source2(){
return terminated(source(), () => { console.log("foo") });
}


for (let item of source2()) {
console.log(item);
break;
}

而且有效!

hello
foo

删除break,你会得到:

hello
world

每次yield后检查

在输入这个答案时,我意识到一个更好的问题/解决方案是在原始生成器方法中找出

我认为将信息传回原始可迭代对象的唯一方法是使用 next(value)。因此,如果我们选择一些唯一的值(比如 Symbol.for("terminated"))来表示终止,并且我们改变上面的 return-hack 来调用 it.next(Symbol.for (“终止”)):

function* source() {
let terminated = yield "hello";
if (terminated == Symbol.for("terminated")) {
console.log("FooBar!");
return;
}
yield "world";
}

function terminator(iterable) {
return {
[Symbol.iterator]() {
const it = iterable[Symbol.iterator]();
const $return = it.return;
it.return = function (value) {
it.next(Symbol.for("terminated"));
return $return.call(it)
}
return it;
}
}
}

for (let item of terminator(source())) {
console.log(item);
break;
}

成功!

hello
FooBar!

链接级联返回

如果您链接了一些额外的转换迭代器,则 return 调用会级联通过它们:

function* chain(source) {
for (let item of source) { yield item; }
}

for (let item of chain(chain(terminator(source())))) {
console.log(item);
break
}

hello
FooBar!

我已经包装了上面的解决方案 as a package .它同时支持 [Symbol.iterator][Symbol.asyncIterator]。我对异步迭代器的情况特别感兴趣,尤其是当需要正确处理某些资源时。

关于javascript - 如何确定 javascript 迭代器是否提前终止?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46414415/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com