问题
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?
回答1:
On 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)
回答2:
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},
}
回答3:
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);
回答4:
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'}
来源:https://stackoverflow.com/questions/55992223/how-to-destructure-results-of-a-dynamic-number-of-async-calls-with-promise-all