ES9の新機能の詳細な説明: 非同期反復

ES9の新機能の詳細な説明: 非同期反復

非同期トラバーサル

非同期トラバーサルを説明する前に、ES6 の同期トラバーサルを思い出してみましょう。

ES6 の定義によると、反復は主に 3 つの部分で構成されます。

反復可能

まず、Iterable の定義を見てみましょう。

インターフェース Iterable {
    [Symbol.iterator]() : イテレータ;
}

Iterable は、このオブジェクトにトラバース可能なデータが含まれており、Iterator を生成できるファクトリ メソッドを実装する必要があることを意味します。

イテレータ

インターフェースイテレータ{
    次の(): イテレータの結果;
}

イテレータは Iterable から構築できます。 Iterator はカーソルに似た概念であり、IteratorResult には next を通じてアクセスできます。

イテレータ結果

IteratorResult は、次のメソッドが呼び出されるたびに取得されるデータです。

インターフェースIteratorResult {
    値: 任意;
    完了: ブール値;
}

取得するデータを表す値に加えて、IteratorResult には、トラバーサルが完了したかどうかを示す done もあります。

以下は配列を反復処理する例です。

> const iterable = ['a', 'b'];

> const iterator = iterable[Symbol.iterator]();

イテレータ.next()

{ 値: 'a'、完了: false }

イテレータ.next()

{ 値: 'b'、完了: false }

イテレータ.next()

{ 値: 未定義、完了: true }

ただし、上記の例では同期データを走査しています。http 側からダウンロードしたファイルなどの非同期データを取得する場合は、ファイルを 1 行ずつ走査する必要があります。データ行の読み取りは非同期操作であるため、非同期データの走査が必要になります。

非同期ファイル読み取りメソッド readLinesFromFile を追加すると、同期トラバーサル メソッドは非同期には適用されなくなります。

// (const line of readLinesFromFile(fileName)) には適用されなくなりました {
    console.log(行);
}

非同期的に 1 行を読み取り、それを同期的に走査する操作を Promise にカプセル化できるのだろうかと疑問に思うかもしれません。

アイデアは良いのですが、この場合、非同期操作が完了したかどうかを検出することは不可能です。したがって、この方法は実行可能ではありません。

そこで ES9 では非同期トラバーサルの概念が導入されました。

1. 非同期反復可能オブジェクトの反復子を取得するには、Symbol.asyncIterator を使用できます。

2. 非同期イテレータの next() メソッドは、IteratorResults を含む Promises オブジェクトを返します。

それでは、非同期トラバーサルの API 定義を見てみましょう。

インターフェースAsyncIterable {
    [Symbol.asyncIterator]() : AsyncIterator;
}
インターフェースAsyncIterator {
    次のメソッド: Promise<IteratorResult>;
}
インターフェースIteratorResult {
    値: 任意;
    完了: ブール値;
}

非同期トラバーサル アプリケーションを見てみましょう。

定数 asyncIterable = createAsyncIterable(['a', 'b']);
asyncIterator は、 .asyncIterable のインスタンスを生成する。
asyncIterator.next()
.then(iterResult1 => {
    console.log(iterResult1); // { 値: 'a'、完了: false }
    asyncIterator.next() を返します。
})
.then(iterResult2 => {
    console.log(iterResult2); // { 値: 'b'、完了: false }
    asyncIterator.next() を返します。
})
.then(iterResult3 => {
    console.log(iterResult3); // { 値: undefined、完了: true }
});

その中で、createAsyncIterable は同期反復可能オブジェクトを非同期反復可能オブジェクトに変換します。次のセクションで、これがどのように生成されるかを見ていきます。

ここでは主に asyncIterator のトラバーサル操作に焦点を当てます。

ES8 では Async 演算子が導入されたため、上記のコードを Async 関数を使用して書き直すこともできます。

非同期関数f(){
    定数 asyncIterable = createAsyncIterable(['a', 'b']);
    asyncIterator は、 .asyncIterable のインスタンスを生成する。
    console.log(asyncIterator.next() を待機します);
        // { 値: 'a'、完了: false }
    console.log(asyncIterator.next() を待機します);
        // { 値: 'b'、完了: false }
    console.log(asyncIterator.next() を待機します);
        // { 値: 未定義、完了: true }
}

非同期反復可能トラバーサル

同期反復可能オブジェクトを走査するには for-of を使用し、非同期反復可能オブジェクトを走査するには for-await-of を使用します。

非同期関数f(){
    await (const x of createAsyncIterable(['a', 'b'])) {
        コンソールログ(x);
    }
}
// 出力:
// は
// ば

await は async 関数内に配置する必要があることに注意してください。

非同期トラバーサルで例外が発生した場合は、for-await-of で try catch を使用して例外をキャッチできます。

関数createRejectingIterable() {
    戻る {
        [シンボル.asyncIterator]() {
            これを返します。
        },
        次() {
            Promise.reject(new Error('Problem!')) を返します。
        },
    };
}
(非同期関数() { 
    試す {
        await (const x of createRejectingIterable()) {
            コンソールログ(x);
        }
    } キャッチ (e) {
        コンソールエラー(e);
            // エラー: 問題!
    }
})();

同期イテラブルは同期イテレータを返し、次のメソッドは {value, done} を返します。

for-await-of を使用すると、同期イテレータは非同期イテレータに変換されます。返された値は Promise に変換されます。

同期 next 自体によって返される値が Promise オブジェクトである場合、非同期の戻り値は同じ Promise のままです。

つまり、次の例に示すように、Iterable<Promise<T>> を AsyncIterable<T> に変換します。

非同期関数main() {
    const syncIterable = [
        Promise.resolve('a')、
        Promise.resolve('b')、
    ];
    await (const x of syncIterable) {
        コンソールログ(x);
    }
}
主要();

// 出力:
// は
// ば

上記の例では、同期 Promise を非同期 Promise に変換します。

非同期関数main() {
    待機(const x of ['a', 'b']) {
        コンソールログ(x);
    }
}
主要();

// 出力:
// は
// d

上記の例では、同期定数を Promise に変換します。 結果は同じであることがわかります。

非同期反復生成

上記の例に戻ると、createAsyncIterable(syncIterable) を使用して syncIterable を AsyncIterable に変換します。

このメソッドがどのように実装されるか見てみましょう:

非同期関数* createAsyncIterable(syncIterable) {
    for (const syncIterable の要素) {
        要素を生成します。
    }
}

上記のコードでは、通常のジェネレーター関数の前に async を追加しています。これは、非同期ジェネレーターであることを意味します。

通常のジェネレーターの場合、 next メソッドが呼び出されるたびに、オブジェクト {value, done} が返されます。このオブジェクトは、yield 値をカプセル化したものです。

非同期ジェネレーターの場合、 next メソッドが呼び出されるたびに、オブジェクト {value, done} を含む promise オブジェクトが返されます。このオブジェクトは、yield 値をカプセル化したものです。

Promise オブジェクトが返されるため、次のメソッドを再度呼び出す前に、非同期実行の結果が完了するのを待つ必要はありません。

Promise.all を使用すると、すべての非同期 Promise 操作を同時に実行できます。

asyncGenObj は、createAsyncIterable を呼び出します。
const [{値:v1},{値:v2}] = await Promise.all([
    asyncGenObj.next()、asyncGenObj.next()
]);
console.log(v1, v2); // アブ

createAsyncIterable では、同期 Iterable から非同期 Iterable を作成します。

次に、非同期 Iterable から非同期 Iterable を作成する方法を見てみましょう。

前のセクションでは、for-await-of を使用して非同期 Iterable からデータを読み取ることができることがわかったので、次のように使用できます。

非同期関数* prefixLines(asyncIterable) {
    for await (asyncIterableのconst行) {
        '> ' + 行を生成します。
    }
}

ジェネレータの記事では、ジェネレータ内でジェネレータを呼び出すことについて説明しました。つまり、プロデューサーでは、yield* を使用して別のジェネレーターが呼び出されます。

同様に、非同期ジェネレータでも同じことを行うことができます。

非同期関数* gen1() {
    'a' を生成します。
    'b' を生成します。
    2を返します。
}
非同期関数* gen2() {
    const 結果 = yield* gen1(); 
        // 結果 === 2
}

(非同期関数() {
    gen2() の const x を待機します。
        コンソールログ(x);
    }
})();
// 出力:
// は
// ば

非同期ジェネレーターで例外がスローされた場合、その例外も Promise にラップされます。

非同期関数* asyncGenerator() {
    新しいエラーをスローします('問題があります!');
}
asyncGenerator().next()
.catch(err => console.log(err)); // エラー: 問題あり!

非同期メソッドと非同期ジェネレーター

非同期メソッドは、 async 関数を使用して宣言され、 Promise オブジェクトを返すメソッドです。

関数内で返される例外またはスローされる例外は、返される Promise の値として使用されます。

(非同期関数() {
    'hello' を返します。
})()
.then(x => console.log(x)); // こんにちは

(非同期関数() {
    新しいエラーをスローします('問題があります!');
})()
.catch(x => console.error(x)); // エラー: 問題あり!

非同期ジェネレーターは、async 関数 * を使用して宣言されたメソッドです。非同期反復可能オブジェクトを返します。

iterable の next メソッドを呼び出すと、Promise が返されます。非同期ジェネレータによって生成された値は、Promise の値を埋めるために使用されます。ジェネレーターで例外がスローされた場合、それは Promise によってもキャッチされます。

非同期関数* gen() {
    'hello' を返します。
}
定数 genObj = gen();
genObj.next().then(x => console.log(x));
    // { 値: 'hello'、完了: false }

以上がES9の新機能である非同期反復の詳細な説明です。ES9の新機能である非同期反復の詳細については、123WORDPRESS.COMの他の関連記事に注目してください。

以下もご興味があるかもしれません:
  • ES6 イテレータトラバーサルの原則、応用シナリオ、関連する共通知識の拡張の詳細な説明
  • ES6 の新機能 2: イテレータ (トラバーサル) と for-of ループの詳細な説明
  • ES6 ディレクトリトラバーサル関数の例
  • ES6 における Iterator と for..of.. トラバーサルの使用法の分析
  • ES9の新機能である正規表現RegExpの詳しい説明
  • ES7 の JavaScript 修飾子を理解する
  • ES7 における Async/await の使用に関する詳細な説明
  • ES7 で Await を使用してコールバックのネストを減らす方法の詳細な説明

<<:  CentOS 7.x のマスターおよびスレーブ DNS サーバーの展開

>>:  Mysqlデータベースの文字化けに対処する方法

推薦する

フラッシュプラグインを使用してPCのカメラを呼び出し、TMLページに埋め込む方法

序文この記事を書いた主な理由は、チームリーダーが、ブラウザを使用してコンピューターのカメラを呼び出し...

Hadoop 2.x と 3.x の 22 ポイントの比較、Hadoop 3.x の 2.x に対する改善点

質問ガイド1. Hadoop 3.x はどのようにして障害を許容するのでしょうか? 2. Hadoo...

CSS で overflow-y: visible; が機能しない理由の分析と解決

シナリオ最近の要件は、モバイル デバイス用の h5 ページです。これには、選択可能なカードの行が必要...

PHP スケジュールバックアップ MySQL および mysqldump 構文パラメータの詳細

まず、MySQL バックアップ コマンド mysqldump の一般的な操作例をいくつか紹介します。...

OpenSSL は双方向認証のチュートリアルを実装します (サーバーとクライアントのコード付き)

1. 背景1.1 問題点最近の製品テスト レポートでは、PKI ベースの認証方法の使用が推奨されて...

HTML の <input> タグの詳細な説明と、それを無効にする方法

定義と使用法<input> タグはユーザー情報を収集するために使用されます。 type ...

MySQL 8.0.22 のインストールと設定方法のグラフィックチュートリアル

この記事ではMySQL 8.0.22のインストールと設定について記録します。具体的な内容は以下のとお...

CSS3を使用してトランジションとアニメーション効果を実現する

JS アニメーションの代わりに CSS アニメーションを使用する必要があるのはなぜですか? Java...

Dockerコンテナのディスクがいっぱいになった場合の状況のまとめ

序文この記事では、最近私が遭遇した 2 つの状況について説明します。今後、新たな発見があれば追加して...

ストリーマーボタンの効果を実現するCSS3アニメーション

CSS3 を学習する過程で、CSS3 属性を使用すると多くのクールな効果を簡単に実現できることが分か...

暗号化における https の Apache 展開の概要

目次目的実験環境実験原理実験手順1. 独立したCAを生成する2. サーバーの秘密鍵と署名要求ファイル...

Dockerでパラメータ変数を外部から指定する方法

この記事は主にDockerでパラメータ変数を外部から指定する方法を紹介します。この記事のサンプルコー...

ウェブページのメモリとCPU使用量を削減する方法

<br />Web ページによっては、サイズは大きくないように見えても開くのに非常に時間...

HTMLでのラジオ値の取得、割り当て、登録の詳細な説明

1. ラジオのグループ化名前が同じであれば、それらはグループであり、つまり、次のようにグループ内で選...