使用中の非同期発電機.並列2での複数のダイナモ質問


Photo by Cameron Venti on Unsplash



回収する
これは、Dynamodbのページ付けと連動してAsyncジェネレータを使用している私のフォローアップです.前回見たように、Asyncジェネレータは「最終的に利用可能な」コレクションを繰り返し処理する便利な方法です.
async function* getPaginatedResults(dynamoClient, params) {
  let lastEvaluatedKey;
  do {
    const queryResult = await dynamoClient.query(params).promise();

    lastEvaluatedKey = queryResult.LastEvaluatedKey;
    params.ExclusiveStartKey = lastEvaluatedKey;

    yield queryResult.Items;
  } while (lastEvaluatedKey);
}

for await (const pageOfItems of getPaginatedResults(dynamoClient, someQueryParams)) {
  // do something with the page of items
}
これは、潜在的にペグ化される可能性のある単一のクエリを作るためのものです.このような複数のクエリを並列で実行する必要がある場合は?まずはNAシリーズアプローチを試してみましょう.

👎 スタックfor-await-of ループ
The for-await-of レギュラーのようにfor ループは、以下のコードが実行されるまで実行されません.
for await (const pageOfItems of getPaginatedResults(dynamoClient, someQueryParams)) {
  // do something with the page of items
}

// <-- Can’t get to here until the loop is over
これは私たちのような場合に問題を起こすことができます.我々がちょうど2を置くならばfor-await-of お互いに隣接しているループ、2番目のクエリーは最初の1ループまですべてのページを通して開始されません.
for await (const pageOfItems of getPaginatedResults(dynamoClient, someQueryParams)) {
  // do something with the page of items
}

// Only when the first query is done can we start the next one.
// If the second query doesn’t depend on the first one’s results,
// running them sequentially is suboptimal.
for await (const pageOfItems of getPaginatedResults(dynamoClient, someOtherQueryParams)) {
  // do something with the page of items
}
ちょうど2を置くように見えますfor-await-of ループは一緒に我々が欲しいものを達成していないので、我々は別のアプローチを探す必要があります.

👍 ラッピングfor-await-of async関数のループ
手続きする前に、単純化のために2つの並列クエリを持っていると仮定しましょう.(それぞれのクエリがページ化されるので、2つの並列のクエリについて潜在的に話をしています).
2つの並列の非同期タスクを継続する前に完了したい場合は、Promise.all , 各タスクの完了を表す約束を渡す
async function task1() {}
async function task2() {}

const p1 = task1();
const p2 = task2();
await Promise.all([p1, p2]);
// ...continue execution
この場合、各タスクはページ化されたクエリです.クエリのすべてのページが処理されたことを示す約束をどうにかすることができれば、上記のスキームを使用することができます.どのように我々はそのような約束を得るのですか?さて、上記の例にはヒントがあります:もし我々が我々の古いを置くならばfor-await-of ループが非同期関数になると、その関数から返された約束は本質的にそのループの完了を表します.それをしましょう
async function paginateQuery(dynamoClient, queryParams) {
  for await (const pageOfItems of getPaginatedResults(dynamoClient, queryParams)) {
    // do something with the page of items
  }
}
さて、これは本当に再利用可能なヘルパーになるためには、ループの本体でパラメータ化する必要があります.以下に例を示します.
async function paginateQuery(dynamoClient, queryParams, callback) {
  for await (const pageOfItems of getPaginatedResults(dynamoClient, queryParams)) {
    await callback(pageOfItems); // optionally break from the loop if callback returns false
  }
}

const usersPromise = paginateQuery(client, usersParams, async (pageOfUsers) => { /* ... */ });
const postsPromise = paginateQuery(client, postsParams, async (pageOfPosts) => { /* ... */ });
await Promise.all([usersPromise, postsPromise]);
// ...continue execution
待って、コールバックを今すぐ対処するには?少し反抗的であるが、我々はこの場合になければならないようです.あなたがどこでもそれを使うと決めるならば、あなたが平行質問を必要とするこのヘルパーを使用するだけであることに注意してください😄.

結論
我々が見たように、直接Aを使ってfor-await-of 非同期発電機を持つループはかなり便利ですが、その制限があります.あなたがよりエレガントな解決策を考えることができるならば、私に知らせてください!