The filter
function keeps only the elements that pass a condition. It gets a function, this time it's called a predicate, and this function returns true/false (truthy and falsy, to be more precise) values. The resulting collection only contains the elements where the predicate returned true.
const arr = [1, 2, 3, 4, 5];
const syncRes = arr.filter((i) => {
return i % 2 === 0;
});
console.log(syncRes);
// 2,4
The async version is a bit more complicated this time and it works in two phases. The first one maps the array through the predicate function asynchronously, producing true/false values. Then the second step is a synchronous filter
that uses the results from the first step.
const arr = [1, 2, 3, 4, 5];
const asyncFilter = async (arr, predicate) => {
const results = await Promise.all(arr.map(predicate));
return arr.filter((_v, index) => results[index]);
}
const asyncRes = await asyncFilter(arr, async (i) => {
await sleep(10);
return i % 2 === 0;
});
console.log(asyncRes);
// 2,4
Or a one-liner implementation:
const asyncFilter = async (arr, predicate) =>
Promise.all(arr.map(predicate))
.then((results) => arr.filter((_v, index) => results[index]));
The above implementation runs all of the predicate functions concurrently. This is usually fine, but, as with all other functions, it might strain some resources too hard. Fortunately, since the above implementation relies on map
, the same concurrency controls can be used.
Instead of using an async map
with a sync filter
, an async reduce
could also do the job. Since it's just one function, the structure is even easier though it does not provide the same level of control.
First, start with an empty array ([]
). Then run the next element through the predicate function and if it passes, append it to the array. If not, skip it.