最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to destructure results of a dynamic number of async calls with Promise.all - Stack Overflow

programmeradmin0浏览0评论

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?

Share Improve this question asked May 5, 2019 at 13:02 Brian PloetzBrian Ploetz 7651 gold badge6 silver badges10 bronze badges 8
  • 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 the call2 variable, and call3 is undefined. – Brian Ploetz Commented May 5, 2019 at 13:22
 |  Show 3 more ments

4 Answers 4

Reset to default 2

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)

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'}
发布评论

评论列表(0)

  1. 暂无评论