概要: このチュートリアルでは、非同期データを順次アクセスできる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
10Code language: JavaScript (javascript)次の表は、イテレーターと非同期イテレーターの違いを示しています。
| # | イテレーター | 非同期イテレーター |
|---|---|---|
| よく知られたシンボル | Symbol.iterator | Symbol.asyncIterator |
next()の戻り値は | {value, done } | {value, done}に解決されるPromise |
| ループ文 | for...of | for await...of |