I need to make an unknown number of async calls in parallel via Promise.all
. Something similar to this:
let externalCalls = [call1()];
if (someCondition1) {
externalCalls.push(call2());
}
if (someCondition2) {
externalCalls.push(call3());
}
Then externalCalls
will be passed to Promise.all
so they can be run in parallel.
Ideally, I'd like to use destructuring of the results so that I can refer to results by name, i.e.
const [call1, call2, call3] = await Promise.all(externalCalls);
I know call1
will always be there, but I don't know if call2
or call3
will be there. So I'd like to define the const
result of calling await Promise.all
dynamically to have the correct properties, Is this possible? Or am I stuck having a generic results array of unknown length, and then having to inspect each item in the results to see which call produced it?
I need to make an unknown number of async calls in parallel via Promise.all
. Something similar to this:
let externalCalls = [call1()];
if (someCondition1) {
externalCalls.push(call2());
}
if (someCondition2) {
externalCalls.push(call3());
}
Then externalCalls
will be passed to Promise.all
so they can be run in parallel.
Ideally, I'd like to use destructuring of the results so that I can refer to results by name, i.e.
const [call1, call2, call3] = await Promise.all(externalCalls);
I know call1
will always be there, but I don't know if call2
or call3
will be there. So I'd like to define the const
result of calling await Promise.all
dynamically to have the correct properties, Is this possible? Or am I stuck having a generic results array of unknown length, and then having to inspect each item in the results to see which call produced it?
-
const [call1, ...rest]
perhaps – P Varga Commented May 5, 2019 at 13:05 -
const [call1, ...restCalls]
? – Dennis Vash Commented May 5, 2019 at 13:05 - it should just work, but it is possible call2, call3 will be undefined. – George Commented May 5, 2019 at 13:16
- @ᆼᆺᆼ Yeah, so this allows a dynamic number of elements after call1, but can you elaborate on how I would then use the rest parameter to figure out which calls were made? – Brian Ploetz Commented May 5, 2019 at 13:20
-
1
@George unfortunately it doesn't work. Let's say I made call1 and call3, if the results const was defined as
[call1, call2, call3]
, the result of call3 is actually in thecall2
variable, andcall3
is undefined. – Brian Ploetz Commented May 5, 2019 at 13:22
4 Answers
Reset to default 2On the one hand, you already know which calls were .push()
ed to externalCalls
, based on someCondition1
, etc.
But perhaps it's better to build externalCalls
in a different way so it always has the same length:
const conditions = [true, someCondition1, etc]
const calls = [call1, call2, etc]
const externalCalls = conditions.map(
(c, i) => c ? calls[i]() : Promise.resolve(null))
const [result1, result2, etc] = await Promise.all(externalCalls)
there is no direct way to know the source of the response of promise.all.
but you can add more information to the response of call1, call2, call3
so your modified code would look like that:
let call1 = fetch(url).then(data1 => ({...data1, source: 'call1'}));
let call2 = fetch(url).then(data2 => ({...data2, source: 'call2'}));
let call3 = fetch(url).then(data3 => ({...data3, source: 'call3'}));
let externalCalls = [call1, call2, call3, etc..];
and in your promise.all response, you can check the source of each returned response like that"
let returnedData = {};
Promise.all(externalCalls).then(allData => {
for(let data of allData){
returnedData[data.source] = data;
console.log(returnedData);
}
});
and when you console returnedData will get something like that:
returnedData = {
'call1': { call1 related data},
'call2': { call2 related data},
'call3': { call3 related data},
}
If someCondition1 is false, you don't push anything, then if someCondition2 is true, you push call3(), so you should expect call3 to be in the second item of the returned array. Therefore, instead you can just return undefined for calls which have no value, keeping the calls in the array having synchronised indexes.
let someCondition1 = false;
let someCondition2 = true;
let call1 = () => Promise.resolve("hello");
let call2 = () => Promise.resolve("world");
let call3 = () => Promise.resolve(":)");
let externalCalls = [
call1(),
someCondition1 ? call2() : undefined,
someCondition2 ? call3() : undefined
];
async function resolveCalls(calls){
const [call1, call2, call3] = await Promise.all(calls);
console.log("call1:", call1);
console.log("call2:", call2);
console.log("call3:", call3);
}
resolveCalls(externalCalls);
My code
const promiseFor1stAPICall = () => {
return new Promise((resolve) => {
return setTimeout(() => {
resolve({ data: "1st api data" });
}, 2000);
});
};
const promiseFor2edAPICall = () => {
return new Promise((resolve) => {
return setTimeout(() => {
resolve({ data: "2ed api data" });
}, 2000);
});
};
const promiseFor3rdAPICall = () => {
return new Promise((resolve) => {
return setTimeout(() => {
resolve({ data: "3rd api data" });
}, 2000);
});
};
const promiseFor4thAPICall = () => {
return new Promise((resolve) => {
return setTimeout(() => {
resolve({ data: "4th api data" });
}, 2000);
});
};
async function destructureFromPromiseAll() {
const promises = [];
promises.length = 4;
const obj = {
condition1: false,
condition2: true,
};
promises[0] = promiseFor1stAPICall();
if (obj.condition1) {
promises[1] = promiseFor2edAPICall();
promises[2] = promiseFor3rdAPICall();
}
if (obj.condition2) {
promises[3] = promiseFor4thAPICall();
}
const data = await Promise.all(promises);
return data;
}
async function log() {
const data = await destructureFromPromiseAll();
const [
firstAPICallRes,
secondAPICallRes,
thirdAPICallRes,
fourthAPICallRes,
] = data;
console.log(
firstAPICallRes,
secondAPICallRes,
thirdAPICallRes,
fourthAPICallRes
);
}
log();
============output===============
{data: '1st api data'}, undefined, undefined, {data: '4th api data'}