Skip to main content

Handle Concurrency

concurrent is a function that can handle multiple asynchronous values at once.

In javascript, there is a function to evaluate multiple promise values at the same time with Promise.all. However, it cannot handle the load of concurrent requests and cannot handle requests for infinite enumerable data sets. concurrent can handle asynchronous requests of infinite datasets and can control the request size of the load.

// 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), // If this line does not exist, it will take a total of 6 seconds.
each(console.log), // 2 seconds
);

You can see that it takes 6 seconds when requesting one by one but takes 2 seconds when requesting using concurrent

Useful Example

A more practical code is below.

If the position of concurrent in the code above is as follows, would the result be different? No, It would be same! Note that concurrent always applies to Iterable before the length is changed.

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

If you want to sequentially evaluate up to map one by one, and evaluate the asynchronous predicate of filter three at the same time, you should write the code below:

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