Conditional/dynamic array promise all

Viewed 19691

I have a function with an array of promises, that array can have from 1 to X promises.

Those promises enter into the array based on conditionals.

I want to be able to distinguish from which API comes each result, and I can't realise a clean way to do it

let promises = [];

if (false) {
  let promise1 = request(toUrl);
  promises.push(promise1);
}
if (true) {
  let promise2 = request(toUrl);
  promises.push(promise2);
}

if (false) {
  let promise3 = request(toUrl);
  promises.push(promise3);
}

if (true) {
  let promise4 = request(toUrl);
  promises.push(promise4);
}

try {
  let result = await Promise.all(promises);
} catch (error) {
  console.log(error);
}

So, if everything goes ok result will be an array of results. Not knowing which one of the conditionals was true, how do I know if result[0] is the result of promise1, promise2 or promise3?

5 Answers

You can just add to the response of your request(url) another information about the promise like

const promise1 = request(url).then(res => ({ res: res, promise: 'promise1' }))

and at the Promise.all() you will get values of the promises in the above form and can detect which promises were resolved.

Example

const promises = [];

if(true) {
   const promise1 = fetch('https://jsonplaceholder.typicode.com/posts/1').then(res => ({ res: res, promise: 'promise1' }));
   promises.push(promise1);
}

if(false) {
   const promise2 = fetch('https://jsonplaceholder.typicode.com/posts/2').then(res => ({ res: res, promise: 'promise2' }));
   promises.push(promise2);
}

Promise.all(promises).then(res => console.log(res));

In my opinion we can simplify the complexity of the problem by using following code -

let promises = [];

let truthyValue = true,
  falsyvalue = true;
  
 let [promise1, promise2, promise3, promise4] = await Promise.all([
    truthyValue ? request(toUrl) : Promise.resolve({}),
    truthyValue ? request(toUrl) : Promise.resolve({}),
    falsyValue ? request(toUrl) : Promise.resolve({}),
    falsyValue ? request(toUrl) : Promise.resolve({})
 ]);
 
 // promise1 will be called only when truthyValue is set
 if (promise1) {
  // do something
 }
 
  // promise2 will be called only when truthyValue is set
  if (promise2) {
  // do something
 }
 
  // promise3 will be called only when falsyValue is set
  if (promise3) {
  // do something
 }
   // promise4 will be called only when falsyValue is set
  if (promise4) {
  // do something
 }

I used an object map of promises with a name key in order to identify which resolve corresponds to which promise.

const promises = {};

const mapResolveToPromise = res => Object.fromEntries(
  Object.entries(promises).map(([key], index) => [key, res[index]])
);

promises.promise1 = fetch('https://jsonplaceholder.typicode.com/posts/1');
promises.promise2 = fetch('https://jsonplaceholder.typicode.com/posts/2');

Promise.all(Object.values(promises))
  .then(mapResolveToPromise)
  .then(res => {
    console.log(res.promise1.url);
    console.log(res.promise2.url);
  });

Why all the pushes, you can construct arrays inline.

doPromiseStuff = async ({ thing = true }) => {
  const urls = ['', '', '', ''];

  return await Promise.all([
    thing ? request(urls[1]) : request(urls[2]),
    thing ? request(urls[3]) : request(urls[4])
  ]);
}

I had a similar problem, always a different quantity of async functions to call. What I didn't want was to start the promises work before promise.all().

So I collected function pointers in an array.

eg:

async function first() {
    return new Promise((resolve)=> setTimeout(resolve,1000,99));
}

async function second() {
    return new Promise((resolve)=> setTimeout(resolve,1500,100));
}

let x = [first, second];
// x is transformed into an array with then executed functions
await Promise.all(x.map(x=>x()))

Result is:

[
    99,
   100
]

hopefully this helps and I understood the mentioned problem ... :)

Related