ENCA 4日目: Iterator Helpers で引数のバリデーションエラー時にイテレーターを閉じる(進行中)
return
メソッド
イテレーターの 昨日の記事でも少し触れていますが、イテレーターにはオプショナルな return
メソッドが定義されています。これは仕様では IteratorClose
内で呼ばれ、イテレーターを閉じます。
interface Iterator {
next(value?: any): IteratorResult;
return?(value?: any): IteratorResult;
throw?(error?: any): IteratorResult;
}
interface IteratorResult {
done: boolean;
value: any;
}
例えば for...of のループの途中で break
, return
, throw
文を使って抜けた際にイテレーターの return
メソッドが呼ばれます。
const iterable = {
[Symbol.iterator]() {
let counter = 0;
let isClosed = false;
return {
next() {
if (isClosed) {
return { done: true, value: undefined };
}
if (counter >= 10) {
isClosed = true;
return { done: true, value: undefined };
}
return { done: false, value: counter++ };
},
return() {
isClosed = true;
console.log("closed");
return { done: true, value: undefined };
},
};
},
};
for (const value of iterable) {
if (value === 5) {
break; // "closed"
}
}
なお余談ですがイテレーターの throw
メソッドはジェネレーター函数に例外が起きたことを通知するために用いられます。詳しくは Masaki Hara さんの記事が参考になります。
return
メソッド
ビルトインイテレーターの ECMAScript のビルトインイテレーターにおいて、ジェネレーター以外には return
メソッドが実装されていません[1]。つまりジェネレーター函数を使う場合や、自身でカスタムイテレーターを実装する場合以外ではあまり閉じられることを考慮しなくても大丈夫です。
このあたりについては uhyo さんの記事が詳しいです。
Iterator Helpers のメソッドで、引数のバリデーションエラー時にイテレーターを閉じる
現状 ES2025 Iterator Helpers で追加されたメソッドでは、与えられた引数のバリデーションエラー時にイテレーターが閉じられません。この挙動は一貫性に欠けると Iterator Sequencing の提案で core-js の作者 zloirock さんから指摘がなされ、PR が作られました。
PR にも書かれていますが ES2025 Set Methods などで、内部でイテレーターを取得し、使用している箇所でちゃんと閉じていることからも、この変更は妥当性があるかなと思います。
(追記)ちょうど今開催中である2024年12月の会議で承認されました。
-
正確には ES2025 Iterator Helpers のメソッドの
%IteratorHelperPrototype%
やIterator.from
でラップする%WrapForValidIteratorPrototype%
でも定義されています。しかしこれらは元のイテレーターが持つreturn
メソッドを呼び出すためのもので、元のイテレーターで実装されていなければ何もしません。 ↩︎
Discussion