ECMAScript/遅延評価の歴史
表示
ECMAScript(ES)における遅延評価の歴史は、言語の進化とともに少しずつ発展してきました。遅延評価は、特にジェネレータ(Generator)やイテレータ(Iterator)の導入によって顕著になり、その後、より高度な機能として導入されています。以下に、ESにおける遅延評価の歴史を時系列で解説します。
ES6(ECMAScript 2015): ジェネレータとイテレータの導入
[編集]ES6は、遅延評価を実現するための重要な機能としてジェネレータとイテレータを導入しました。
ジェネレータ(Generator)
[編集]- ジェネレータは、
function*構文を使って定義され、yieldキーワードを使って値を逐次的に生成します。 - ジェネレータは、値を必要に応じて生成する(遅延評価)ことが可能です。
例: ジェネレータを使った遅延評価
[編集]function* generateNumbers() { yield 1; yield 2; yield 3; } const generator = generateNumbers(); console.log(generator.next().value); // 1 console.log(generator.next().value); // 2 console.log(generator.next().value); // 3
イテレータ(Iterator)
[編集]- イテレータは、
Symbol.iteratorメソッドを実装したオブジェクトで、next()メソッドを使って値を逐次的に取得します。 - イテレータも遅延評価を実現するための基盤となります。
例: イテレータを使った遅延評価
[編集]const iterable = { [Symbol.iterator]() { let count = 0; return { next() { count++; return { value: count, done: count > 3 }; }, }; }, }; for (const value of iterable) { console.log(value); // 1, 2, 3 }
ES2018: 非同期ジェネレータと非同期イテレータ
[編集]ES2018では、非同期ジェネレータと非同期イテレータが導入され、非同期処理における遅延評価が可能になりました。
非同期ジェネレータ(Async Generator)
[編集]- 非同期ジェネレータは、
async function*構文を使って定義され、yieldを使って非同期に値を生成します。
例: 非同期ジェネレータを使った遅延評価
[編集]async function* generateAsyncNumbers() { yield 1; yield 2; yield 3; } (async () => { const asyncGenerator = generateAsyncNumbers(); for await (const value of asyncGenerator) { console.log(value); // 1, 2, 3 } })();
非同期イテレータ(Async Iterator)
[編集]- 非同期イテレータは、
Symbol.asyncIteratorメソッドを実装したオブジェクトで、next()メソッドがPromiseを返します。
例: 非同期イテレータを使った遅延評価
[編集]const asyncIterable = { [Symbol.asyncIterator]() { let count = 0; return { async next() { count++; return { value: count, done: count > 3 }; }, }; }, }; (async () => { for await (const value of asyncIterable) { console.log(value); // 1, 2, 3 } })();
ES2020: Promise.allSettled と遅延評価
[編集]ES2020では、Promise.allSettled が導入され、非同期処理における遅延評価の柔軟性が向上しました。
Promise.allSettled
[編集]Promise.allSettledは、すべてのPromiseが解決または拒否されるまで待機し、その結果を配列として返します。- この機能は、非同期処理の遅延評価をより柔軟に制御するために役立ちます。
例: Promise.allSettled を使った遅延評価
[編集]const promises = [ Promise.resolve(1), Promise.reject("Error"), Promise.resolve(3), ]; Promise.allSettled(promises).then((results) => { results.forEach((result) => console.log(result)); // { status: 'fulfilled', value: 1 } // { status: 'rejected', reason: 'Error' } // { status: 'fulfilled', value: 3 } });
ES2021: WeakRef と FinalizationRegistry
[編集]ES2021では、WeakRef と FinalizationRegistry が導入され、弱参照を使った遅延評価が可能になりました。
WeakRef
[編集]WeakRefは、オブジェクトへの弱い参照を作成し、ガベージコレクションの対象となることを許容します。
例: WeakRef を使った遅延評価
[編集]let obj = { data: "example" }; const weakRef = new WeakRef(obj); obj = null; // obj への強い参照がなくなる setTimeout(() => { console.log(weakRef.deref()); // undefined (GCが発生した場合) }, 1000);
FinalizationRegistry
[編集]FinalizationRegistryは、オブジェクトがガベージコレクションされたときにコールバックを実行するための仕組みです。
例: FinalizationRegistry を使った遅延評価
[編集]const registry = new FinalizationRegistry((heldValue) => { console.log(`Object with value ${heldValue} was garbage collected`); }); let obj = { data: "example" }; registry.register(obj, "some value"); obj = null; // obj への強い参照がなくなる // GCが発生すると、コールバックが実行される
まとめ
[編集]ECMAScriptにおける遅延評価の歴史は、以下のように進化してきました:
- ES6: ジェネレータとイテレータの導入により、基本的な遅延評価が可能に。
- ES2018: 非同期ジェネレータと非同期イテレータの導入により、非同期処理における遅延評価が実現。
- ES2020:
Promise.allSettledの導入により、非同期処理の遅延評価が柔軟に。 - ES2021:
WeakRefとFinalizationRegistryの導入により、弱参照を使った遅延評価が可能に。