Skip to content

並行処理

concurrentは、複数の非同期値を一度に処理できる関数です。

JavaScript には、Promise.allで複数の promise 値を同時に評価する関数があります。 しかし、同時リクエストの負荷を処理できず、無限の列挙可能なデータセットへのリクエストを処理できません。 concurrentは、無限データセットの非同期リクエストを処理し、負荷のリクエストサイズを制御できます。

ts
// prettier-ignore
import { pipe, toAsync, range, map, filter, take, each, concurrent } from "@fxts/core";

const fetchApi = (page) =>
  new Promise((resolve) => setTimeout(() => resolve(page), 1000));

await pipe(
  range(Infinity),
  toAsync,
  map(fetchApi), // 0,1,2,3,4,5
  filter((a) => a % 2 === 0),
  take(3), // 0,2,4
  concurrent(3), // この行がないと、合計6秒かかります。
  each(console.log), // 2秒
);

1 つずつリクエストすると 6 秒かかりますが、concurrentを使用すると 2 秒で完了することがわかります。

実用的な例

より実践的なコードは以下の通りです。

上記のコードでconcurrentの位置が以下のようになった場合、結果は変わるでしょうか? いいえ、同じです!concurrentは常に長さが変更される前のIterableに適用されることに注意してください。

ts
await pipe(
  range(Infinity),
  toAsync,
  map(fetchApi),
  concurrent(3),
  filter((a) => a % 2 === 0),
  take(3),
  each(console.log),
);

mapまで順番に 1 つずつ評価し、 filterの非同期 predicate を 3 つ同時に評価したい場合は、以下のコードを記述する必要があります:

ts
await pipe(
  range(Infinity),
  toAsync,
  map(fetchApi),
  toArray,
  filter((a) => delay(100, a % 2 === 0)),
  take(3),
  concurrent(3),
  each(console.log),
);

Released under the Apache-2.0 License.