JavaScriptでは、Symbol.asyncIteratorを使用することで非同期のイテレーション処理を実装できます。この記事では、Symbol.asyncIteratorの基本的な使い方と実践的な例を紹介します。
Symbol.asyncIteratorとは
Symbol.asyncIteratorは、オブジェクトの非同期イテレーションプロトコルを定義するためのSymbolです。これを実装することで、for await...of文を使用して非同期にデータを取得できます。
基本的な実装方法
const asyncIterable = {
[Symbol.asyncIterator]() {
return {
i: 0,
async next() {
if (this.i < 3) {
return { value: this.i++, done: false };
}
return { value: undefined, done: true };
}
};
}
};
async function example() {
for await (const value of asyncIterable) {
console.log(value); // 0, 1, 2
}
}
example();実践的な使用例
APIからデータを取得する例
class AsyncDataFetcher {
constructor(urls) {
this.urls = urls;
this.index = 0;
}
[Symbol.asyncIterator]() {
return {
urls: this.urls,
index: 0,
async next() {
if (this.index < this.urls.length) {
const response = await fetch(this.urls[this.index]);
const data = await response.json();
this.index++;
return { value: data, done: false };
}
return { value: undefined, done: true };
}
};
}
}
// 使用例
const urls = [
'https://api.example.com/data1',
'https://api.example.com/data2',
'https://api.example.com/data3'
];
const fetcher = new AsyncDataFetcher(urls);
async function fetchData() {
for await (const data of fetcher) {
console.log(data);
}
}ストリーミングデータの処理
class DataStream {
constructor() {
this.data = [];
this.subscribers = [];
}
addData(value) {
this.data.push(value);
this.subscribers.forEach(fn => fn());
}
[Symbol.asyncIterator]() {
let index = 0;
return {
next: () => {
return new Promise(resolve => {
const checkData = () => {
if (index < this.data.length) {
resolve({ value: this.data[index++], done: false });
} else {
this.subscribers.push(checkData);
}
};
checkData();
});
}
};
}
}エラーハンドリング
非同期イテレーターでのエラー処理は、try-catchブロックを使用して行います:
async function handleAsyncIteration() {
try {
for await (const value of asyncIterable) {
console.log(value);
}
} catch (error) {
console.error('エラーが発生しました:', error);
}
}パフォーマンスの考慮事項
- メモリ使用量を考慮し、必要に応じてイテレーターをクリーンアップする
- 大量のデータを処理する場合は、バッチ処理を検討する
- 無限ループを避けるため、適切な終了条件を設定する
Symbol.asyncIteratorは、非同期データの取り扱いを効率的に行うための強力な機能です。APIとの通信やストリーミングデータの処理など、様々なユースケースで活用できます。適切に実装することで、より柔軟で保守性の高いコードを作成することができます。