Dun Peal
Dun Peal

Reputation: 17689

Composing Promises and non-promise values

I have some code that essentially looks like this:

let foos = ['foo', 'foo', 'foo'];
let bars = foos.map(foo => new Promise(resolve => resolve(foo + ' processed')));
function f(foo, bar) { '...' };

As you can see, f() requires a foo and a bar argument. The problem is that bar is a Promise. Had f() only required bar, I would do:

Promise.all(bars).then(values => values.map(f));

However, f() requires both the bar value resulting from the Promise and its matching non-promise foo, so I'm not sure what's the best way to code this?

Upvotes: 1

Views: 124

Answers (3)

Felix Kling
Felix Kling

Reputation: 816790

.map passes the index of the element to the callback too, so you could do

Promise.all(bars).then(
   values => values.map((value, i) => f(foos[i], value))
);

Upvotes: 3

Roamer-1888
Roamer-1888

Reputation: 19288

If foos is not in scope of the Promise.all().then() handler, then you need to ensure that foos as well as bars are delivered down the promise chain.

Here's a couple of approaches :

1. Deliver an array of objects

Each object will contain a foo and its corresponding bar.

let foos = ['foo', 'foo', 'foo'];
let promises = foos.map(foo => new Promise(resolve => resolve({
    unprocessed: foo,
    processed: foo + ' processed'
})));
// ...
Promise.all(promises).then(results => results.map(obj => f(obj.unprocessed, obj.processed)));

Demo

2. Deliver an object of arrays

The object will contain a foos array and a congruant bars array.

let foos = ['foo', 'foo', 'foo'];
let promise = Promise.all(foos.map(foo => new Promise(resolve => resolve(foo + ' processed'))))
    .then(bars => ({ 'unprocessed': foos, 'processed': bars }));
// ...
promise.then(obj => obj.unprocessed.map((foo, i) => f(foo, obj.processed[i])));

Demo

(1) is arguably less messy than (2).

Upvotes: 1

jib
jib

Reputation: 42490

(Adhering to the restriction mentioned in comments that foos is not in scope...)

You can pass the extra argument down the chain a little smoother using ES6 destructuring:

let foos = ['foo', 'foo', 'foo'];
let bars = foos.map(foo => new Promise(res => res([foo, foo + ' processed'])));
Promise.all(bars).then(values => values.map(([foo, bar]) => f(foo, bar)));

Upvotes: 0

Related Questions