Explosion Pills Explosion Pills - 6 months ago 15
Javascript Question

Functional operations (such as filtering) on promises

I am performing several queries simultaneously and creating an array of promises from them. I want the resulting array to only have certain properties returned from the query, and I want to filter others (but these operations could really be anything). Currently, I have:

Promise.all(Ids.map(Id => query(Id)
.then(result => result.Item)
)).then(results => results.filter(Boolean));

The internal
is still done in parallel, so I think this is okay, but I don't like this for two reasons:

  1. I have an internal / nested promise chain I would like to flatten

  2. The outer filtering has to wait for all promises to complete (expected) and then iterate over the entire result (bad). It would be preferable not to add empty items in the first place.

Is there a preferred way to perform functional operations on a collection of promises?


One way is to use Reactive Extensions library, which provides a way to integrate different models for asynchronicity into a conceptual "stream" model. E.g. the code you have up there (assuming Ids is an array and query returns a promise) would turn into this:

    .flatMap(id => query(id))
    .map(result => result.Item)
    .filter(item => item.filterByThis) // Not sure what Boolean is supposed to be in your code

Assuming Ids is an number[], we start out by producing an Observable<number>, then pass it through various familiar looking operators to transform and filter the stream, then finally use toArray get an observable that emits a single array of whatever type result.Item is supposed to be.

You can think of Observables as a generalization of the concept of promises to asynchronous operations that return any number of values, rather than just one. This is a powerful paradigm, and the Rx library is pretty popular in many languages. You can read more about it here or get started with this npm package.