概要: このチュートリアルでは、非同期データを順次アクセスできるJavaScript非同期イテレーターについて学習します。
JavaScript非同期イテレーター入門
ES6では、データを順次アクセスできるイテレーターインターフェースが導入されました。イテレーターは、配列、セット、マップなどの同期データソースへのアクセスに適しています。
イテレーターインターフェースの主要なメソッドはnext()
で、{value, done}
オブジェクトを返します。ここで、done
はシーケンスの終わりに達したかどうかを示すブール値であり、value
はシーケンスで生成された値です。
同期データとは、シーケンス内の次のvalue
とdone
の状態が、next()
メソッドが返された時点で既知であることを意味します。
同期データソース以外にも、JavaScriptはI/Oアクセスなどの非同期データソースにアクセスする必要があります。非同期データソースの場合、イテレーターのvalue
とdone
の状態は、next()
メソッドが返された時点では多くの場合不明です。
非同期データソースに対処するために、ES2018では非同期イテレーター(または非同期イテレータ)インターフェースが導入されました。
非同期イテレーターはイテレーターに似ていますが、そのnext()
メソッドは、{value, done}
オブジェクトに解決されるPromiseを返す点が異なります。
以下は、イテレーターインターフェースを実装するSequence
クラスを示しています。(Sequence
クラスの実装方法の詳細については、イテレーターチュートリアルを参照してください。)
class Sequence {
constructor(start = 0, end = Infinity, interval = 1) {
this.start = start;
this.end = end;
this.interval = interval;
}
[Symbol.iterator]() {
let counter = 0;
let nextIndex = this.start;
return {
next: () => {
if (nextIndex <= this.end) {
let result = {
value: nextIndex,
done: false
}
nextIndex += this.interval;
counter++;
return result;
}
return {
value: counter,
done: true
};
}
}
}
}
Code language: JavaScript (javascript)
このSequence
クラスを非同期にするには、次のように変更する必要があります。
Symbol.iterator
の代わりにSymbol.asyncIterator
を使用します。next()
メソッドからPromiseを返します。
次のコードは、Sequence
クラスをAsyncSequence
クラスに変換します。
class AsyncSequence {
constructor(start = 0, end = Infinity, interval = 1) {
this.start = start;
this.end = end;
this.interval = interval;
}
[Symbol.asyncIterator]() {
let counter = 0;
let nextIndex = this.start;
return {
next: async () => {
if (nextIndex <= this.end) {
let result = {
value: nextIndex,
done: false
}
nextIndex += this.interval;
counter++;
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(result);
}, 1000);
});
}
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
value: counter,
done: true
});
}, 1000);
});
}
}
}
}
Code language: JavaScript (javascript)
AsyncSequence
は、1秒ごとにシーケンスの次の数値を返します。
for await...of文
非同期イテラブルオブジェクトを反復処理するには、ES2018でfor await...of
文が導入されました。
for await (variable of iterable) {
// statement
}
Code language: JavaScript (javascript)
await
キーワードはasync
関数でのみ使用できるため、次のようにAsyncSequence
クラスを使用する非同期IIFEを作成できます。
(async () => {
let seq = new AsyncSequence(1, 10, 1);
for await (let value of seq) {
console.log(value);
}
})();
Code language: JavaScript (javascript)
出力(各数値は1秒ごとに返されます)
1
2
3
4
5
6
7
8
9
10
Code language: JavaScript (javascript)
次の表は、イテレーターと非同期イテレーターの違いを示しています。
# | イテレーター | 非同期イテレーター |
---|---|---|
よく知られたシンボル | Symbol.iterator | Symbol.asyncIterator |
next() の戻り値は | {value, done } | {value, done} に解決されるPromise |
ループ文 | for...of | for await...of |