Filtering an array with a function that returns a promise

array filter async/await
async push to array
react convert promise to array
promise map
p-iteration
lodash async filter
promise inside array filter
promises push

Given

let arr = [1,2,3];

function filter(num) {
  return new Promise((res, rej) => {
    setTimeout(() => {
      if( num === 3 ) {
        res(num);
      } else {
        rej();
      }
    }, 1);
  });
 }

 function filterNums() {
   return Promise.all(arr.filter(filter));
 }

 filterNums().then(results => {
   let l = results.length;
   // length should be 1, but is 3
 });

The length is 3 because Promises are returned, not values. Is there a way to filter the array with a function that returns a Promise?

Note: For this example, fs.stat has been replaced with setTimeout, see https://github.com/silenceisgolden/learn-esnext/blob/array-filter-async-function/tutorials/array-filter-with-async-function.js for the specific code.

As mentioned in the comments, Array.prototype.filter is synchronous and therefore does not support Promises.

Since you can now (theoretically) subclass built-in types with ES6, you should be able to add your own asynchronous method which wraps the existing filter function:

Note: I've commented out the subclassing, because it's not supported by Babel just yet for Arrays

class AsyncArray /*extends Array*/ {
  constructor(arr) {
    this.data = arr; // In place of Array subclassing
  }

  filterAsync(predicate) {
     // Take a copy of the array, it might mutate by the time we've finished
    const data = Array.from(this.data);
    // Transform all the elements into an array of promises using the predicate
    // as the promise
    return Promise.all(data.map((element, index) => predicate(element, index, data)))
    // Use the result of the promises to call the underlying sync filter function
      .then(result => {
        return data.filter((element, index) => {
          return result[index];
        });
      });
  }
}
// Create an instance of your subclass instead
let arr = new AsyncArray([1,2,3,4,5]);
// Pass in your own predicate
arr.filterAsync(async (element) => {
  return new Promise(res => {
    setTimeout(() => {
      res(element > 3);
    }, 1);
  });
}).then(result => {
  console.log(result)
});

Babel REPL Demo

Promise.filter, Promise.filter( Iterable<any>|Promise<Iterable<any>> input, function(any item, int index, into an array and filter the array to another using the given filterer function. Promise.map(valuesToBeFiltered, function(value, index, length) { return  Given an Iterable (arrays are Iterable ), or a promise of an Iterable, which produces promises (or a mix of promises and values), iterate over all the values in the Iterable into an array and filter the array to another using the given filterer function.

Here is a 2017 elegant solution using async/await :

Very straightforward usage:

const results = await filter(myArray, async num => {
  await doAsyncStuff()
  return num > 2
})

The helper function (copy this into your web page):

async function filter(arr, callback) {
  const fail = Symbol()
  return (await Promise.all(arr.map(async item => (await callback(item)) ? item : fail))).filter(i=>i!==fail)
}

Demo:

// Async IIFE
(async function() {
  const myArray = [1, 2, 3, 4, 5]

  // This is exactly what you'd expect to write 
  const results = await filter(myArray, async num => {
    await doAsyncStuff()
    return num > 2
  })

  console.log(results)
})()


// Arbitrary asynchronous function
function doAsyncStuff() {
  return Promise.resolve()
}


// The helper function
async function filter(arr, callback) {
  const fail = Symbol()
  return (await Promise.all(arr.map(async item => (await callback(item)) ? item : fail))).filter(i=>i!==fail)
}

Immutability, Map, Filter - DEV Community ‍ ‍ , isEven function returns a promise so I add each and every promise into “Promise.​all” method. “Promise.all” method takes an array of Promises  const filter = require (' promise-filter ') Promise. resolve ([1, 2, 3]) . then (filter ((val) => val >= 2)) // => [2, 3] Why? This module is basically equivalent to bluebird.filter , but it's handy to have the one function you need instead of a kitchen sink.

Here's a way:

var wait = ms => new Promise(resolve => setTimeout(resolve, ms));
var filter = num => wait(1).then(() => num == 3);

var filterAsync = (array, filter) =>
  Promise.all(array.map(entry => filter(entry)))
  .then(bits => array.filter(entry => bits.shift()));

filterAsync([1,2,3], filter)
.then(results => console.log(results.length))
.catch(e => console.error(e));

The filterAsync function takes an array and a function that must either return true or false or return a promise that resolves to true or false, what you asked for (almost, I didn't overload promise rejection because I think that's a bad idea). Let me know if you have any questions about it.

var wait = ms => new Promise(resolve => setTimeout(resolve, ms));
var filter = num => wait(1).then(() => num == 3);

var filterAsync = (array, filter) =>
  Promise.all(array.map(entry => filter(entry)))
  .then(bits => array.filter(entry => bits.shift()));

filterAsync([1,2,3], filter)
.then(results => console.log(results.length))
.catch(e => console.error(e));

var console = { log: msg => div.innerHTML += msg + "<br>",
                error: e => console.log(e +", "+ (e.lineNumber-25)) };
<div id="div"></div>

Making array iteration easy when using async/await, This means that an async function has to be passed as iteratee if we are to besides a Promise is passed to await, it just returns the value as-is. In this case we are passing an Array of Promises instead of a The following methods have been implemented as well: find(), findIndex(), some(), every(), filter()  The filter() method creates a new array with all the elements that pass the test implemented by the callback() function. Internally, the filter() method iterates over each element of the array and pass each element to the callback function. If the callback function returns true, it includes the element in the return array. The filter() method accepts two named arguments: a callback function and an optional object.

For typescript folk (or es6 just remove type syntax)

function mapAsync<T, U>(array: T[], callbackfn: (value: T, index: number, array: T[]) => Promise<U>): Promise<U[]> {
  return Promise.all(array.map(callbackfn));
}

async function filterAsync<T>(array: T[], callbackfn: (value: T, index: number, array: T[]) => Promise<boolean>): Promise<T[]> {
  const filterMap = await mapAsync(array, callbackfn);
  return array.filter((value, index) => filterMap[index]);
}

es6

function mapAsync(array, callbackfn) {
  return Promise.all(array.map(callbackfn));
}

async function filterAsync(array, callbackfn) {
  const filterMap = await mapAsync(array, callbackfn);
  return array.filter((value, index) => filterMap[index]);
}

How to use async functions with Array.filter in Javascript, This article is part of a series on Asynchronous array functions in const results = await Promise.all(arr.map(predicate)); return arr.filter((_v,  This function flattens nested layers of promise-like objects (e.g. a promise that resolves to a promise that resolves to something) into a single layer. The Promise.resolve() method returns a Promise object that is resolved with a given value.

Promise Reducer to the rescue!

[1, 2, 3, 4].reduce((op, n) => {
    return op.then(filteredNs => {
        return new Promise(resolve => {
            setTimeout(() => {
                if (n >= 3) {
                    console.log("Keeping", n);
                    resolve(filteredNs.concat(n))
                } else {
                    console.log("Dropping", n);
                    resolve(filteredNs);
                }
            }, 1000);
        });
    });
}, Promise.resolve([]))
.then(filteredNs => console.log(filteredNs));

Reducers are awesome. "Reduce my problem to my goal" seems to be a pretty good strategy for anything more complex than what the simple tools will solve for you, i.e. filtering an array of things that aren't all available immediately.

JavaScript async and await in loops, We'll look at how await affects forEach , map , and filter in the next few sections. (Notice the async keyword in the callback function. We need this async If you use await in a map , map will always return an array of promise. filter() calls a provided callback function once for each element in an array, and constructs a new array of all the values for which callback returns a value that coerces to true. callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values.

How to use Async and Await with Array.prototype.map(), You want to execute an async function inside a map() call, to perform //a function that returns a promise return Promise.resolve('ok') } const  @RonRoyston - First off, the function you pass to .then() is a separate function from the containing function so when it is called, it has its own return value. Secondly, the return value from a .then() handler becomes the resolved value of the promise.

Array.prototype.filter(), filter() calls a provided callback function once for each element in an array, and constructs a new array of all the values for which callback returns  The FILTER function will return an array, which will spill if it's the final result of a formula. This means that Excel will dynamically create the appropriate sized array range when you press ENTER .

How to use a promise value for an array filter method?, I need to return the boolean result of a file readAsText promise to an array filter method. The promise returns the correct value, based on the  A Promise can be created from scratch using its constructor. This should be needed only to wrap old APIs. In an ideal world, all asynchronous functions would already return promises. Unfortunately, some APIs still expect success and/or failure callbacks to be passed in the old way. The most obvious example is the setTimeout () function:

Comments
  • "Is there a way to filter the array with a function that returns a Promise?" Certainly not with using Array#filter.
  • @FelixKling That is what I'm concluding as well, but can you explain the why behind this further? I'm not comprehending why this is the case; it does seem semi-logical to me.
  • because filter expects a function which returns a boolean, not a promise object
  • @JonahWilliams Yes, I understand that. Changing the filter function to an async function produces the same results, so I'm guessing that also returns a promise instead of the await waiting for the returned boolean.
  • This is invalid since super() must be called before any assignment to this inside constructor
  • @FarzadYZ The implementation of subclass was just an example. You wouldn't need a constructor with true subclassing, as you would be using the base Array constructor and not using your own data store
  • You're right, I was just warning for the folks who blindly copy-paste the accepted answer :)
  • @FarzadYZ Ah good point, it does look like you can just uncomment that block and have it work...
  • This has a subtle difference in behaviour to normal Array.filter: if you try to filter an array in a way that includes undefined elements, you'll lose them. E.g. filter([1, 2, undefined, 3], (x) => x !== 1) will return [2, 3], not [2, undefined, 3], as it should.
  • @TimPerry correct, feel free to revise the answer so something that makes more sense :)
  • One option would be to return a Symbol sentinel value instead of undefined.
  • @Tamlyn added Symbol sentinel to fix undefined situation :)
  • This is a great answer. Only tweak I made was to add readonly to the array parameter types.
  • great point! Moreover, as of now there is even Promise.filter in Bluebird bluebirdjs.com/docs/api/promise.filter.html
  • FYI the async/await keywords are ES7 (Candidate) not ES6