How to destructure results of a dynamic number of async calls with Promise.all

怎甘沉沦 提交于 2020-08-08 06:24:41

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!