カテゴリー
【Javascript基礎講座】AsyncGeneratorを正しく初期化する
※ 当ページには【広告/PR】を含む場合があります。
2024/04/18

通常のfor構文に見るイタレーターと比較して、イマイチ認知度の低い仕組みの一つに「ジェネレーター」があります。
イタレーターもジェネレーターも繰り返し処理を行う意味では似たように感じられるかもしれませんが、Javascriptの何らかのコードを書いている時に、イタレーターよりもジェネレーターの方が好ましいケースも結構あります。
基本的なジェネレーターの特徴と使い方は以前の記事で簡単に触れています。
さらに言うと、ジェネレーターに非同期処理を行わせたい場合には、
少し困るのが、AsyncGeneratorの初期化方法です。
今回はちょっとしたことですが、AsyncGeneratorについて学んでみましょう。
AsyncGeneratorの基本的な使い方
まず基本的な使い方から振り返ってみます。
Javascriptから
AsyncGenerator
function*
async
const generator = async function*() {
yield* await Promise.resolve([1, 2, 3]);
};
//👇await generator()とならないことに注意
const gen = generator();
console.log(await gen.next());
console.log(await gen.next());
console.log(await gen.next());
console.log(await gen.next());
これを実行すると、
{ value: 1, done: false }
{ value: 2, done: false }
{ value: 3, done: false }
{ value: undefined, done: true }
というように
next
ここで
AsyncGenerator
通常よく慣れ親しんでいる
async function
Promise
const gen = await generator()
await
ですが、
async function*
AsyncGenerator
await
「Async...」を冠する名前から少し誤解を生みそうですが、
もう一例やってみます。
AsyncGenerator
const generator = async function*(data) {
yield* data;
};
const data = await Promise.resolve([1, 2, 3]);
const gen = generator(data);
console.log(await gen.next());
console.log(await gen.next());
console.log(await gen.next());
console.log(await gen.next());
これを実行すると先程と同じ結果が得られます。
{ value: 1, done: false }
{ value: 2, done: false }
{ value: 3, done: false }
{ value: undefined, done: true }
AsyncGeneratorをクラスのメンバ変数として初期化する
もう少し
AsyncGenerator
AsyncGenerator
関連するテーマとして以前詳しく説明していた、
コンストラクタが"同期的"なので、
AsyncGenerator
class HogeClass {
constructor() {
this.gen = initHogeAsyncGenerator();
}
initHogeAsyncGenerator = async function*() {
yield* await Promise.resolve([1, 2, 3]);
};
}
const hoge = new HogeClass();
console.log(await hoge.gen.next());
console.log(await hoge.gen.next());
console.log(await hoge.gen.next());
console.log(await hoge.gen.next());
これを実行しても先程と同じ結果が得られます。
{ value: 1, done: false }
{ value: 2, done: false }
{ value: 3, done: false }
{ value: undefined, done: true }
問題になってしまうのが、
AsyncGenerator
つまり、
class HogeClass {
constructor() {
this.gen = initHogeAsyncGenerator();
//👇コンストラクタ内部でPromise型の中身は解決できない
const data = await Promise.resolve([1, 2, 3]);
this.gen = initHogeAsyncGenerator(data);
}
initHogeAsyncGenerator = async function*(data) {
yield* data;
};
}
const hoge = new HogeClass();
//...
ということで、
AsyncGenerator
class HogeClass {
constructor() {}
initHogeAsyncGenerator = async function*(data) {
yield* data;
};
static async initHogeFactory() {
const obj = new HogeClass();
//👇ここで非同期に初期化させたい値を引き出す
const lazyData = await Promise.resolve([1, 2, 3]);
obj.gen = obj.initHogeAsyncGenerator(lazyData);
return obj;
}
}
const hoge = await HogeClass.initHogeFactory();
console.log(await hoge.gen.next());
console.log(await hoge.gen.next());
console.log(await hoge.gen.next());
console.log(await hoge.gen.next());
これを実行すると期待した結果が得られます。
{ value: 1, done: false }
{ value: 2, done: false }
{ value: 3, done: false }
{ value: undefined, done: true }
まとめ
今回は
AsyncGenerator
どこがどう同期・非同期ということを考えながらでないと、いざエラーが出てしまったときにバグが発見しにくいので、躓く前に一度じっくりと用法の基本を理解してみてください。
記事を書いた人
ナンデモ系エンジニア
主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。
カテゴリー