Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Array.prototype.filter with async?

Background

I am trying to filter an array of objects. Before I filter, I need to convert them to some format, and this operation is asynchronous.

 const convert = () => new Promise( resolve => {      setTimeout( resolve, 1000 );  }); 

So, my first try was to do something like the following using async/await:

const objs = [ { id: 1, data: "hello" }, { id: 2, data: "world"} ];  objs.filter( async ( obj ) => {     await convert();     return obj.data === "hello"; }); 

Now, as some of you may know, Array.protoype.filter is a function which callback must return either true or false. filter is synchronous. In the previous example, I am returning none of them, I return a Promise ( all async functions are Promises ).

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter

So as one can assume, the code before doesn't really work... That assumption is correct.

Problem

To make filter work with an async function, I checked stackoverflow and found this topic:

Filtering an array with a function that returns a promise

Unfortunately, the chosen answer is overly complex and uses classes. This won't do for me. I am instead looking for a more simple solution, using simple functions with a functional approach.

There is one solution at the very end, using a map with a callback to simulate a filter:

https://stackoverflow.com/a/46842181/1337392

But I was hoping to fix my filter function, not to replace it.

Questions

  • Is there a way to have an async function inside a filter?
  • If not, what is the simplest replacement I can do?
like image 506
Flame_Phoenix Avatar asked Nov 03 '17 11:11

Flame_Phoenix


People also ask

Are array filters asynchronous?

Array. filter is not an asynchronous method, but what you appear to be confusing is the order of execution of a JavaScript programme. When the browser parses your code, the browser will look for named functions and add them to the list of declared names in the current scope (known as function hoisting).

Is filter synchronous or asynchronous?

filter is a function which callback must return either true or false. filter is synchronous.

What is array prototype filter useful for?

Array.prototype.filter() The filter() method creates a shallow copy of a portion of a given array, filtered down to just the elements from the given array that pass the test implemented by the provided function.

Can async return an array?

We have to call the async function from another function which can be asynchronous or synchronous (We can pass the array or choose to declare the array in the async function itself) and then return the array from the async function. The basic approach is to include a try-catch block.


2 Answers

There is no way to use filter with an async function (at least that I know of). The simplest way that you have to use filter with a collection of promises is to use Promise.all and then apply the function to your collection of results. It would look something like this:

const results = await Promise.all(your_promises) const filtered_results = results.filter(res => //do your filtering here) 

Hope it helps.

like image 185
mcousillas Avatar answered Oct 04 '22 13:10

mcousillas


Adapted from the article How to use async functions with Array.filter in Javascript by Tamás Sallai, you basically have 2 steps:

  1. One that creates the conditions for an object to pass
  2. One that receives the objects and returns true or false according to conditions

Here's an example

const arr = [1, 2, 3, 4, 5];  function sleep(ms) {       return new Promise((resolve) => setTimeout(resolve, ms));     }  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 
like image 24
ce-loco Avatar answered Oct 04 '22 13:10

ce-loco