2
votes

Comment déstructurer les résultats d'un nombre dynamique d'appels asynchrones avec Promise.all

J'ai besoin de faire un nombre inconnu d'appels asynchrones en parallèle via Promise.all . Quelque chose de similaire à ceci:

const [call1, call2, call3] = await Promise.all(externalCalls);

Ensuite, externalCalls sera transmis à Promise.all afin qu'ils puissent être exécutés en parallèle. P >

Idéalement, j'aimerais utiliser la déstructuration des résultats pour pouvoir faire référence aux résultats par leur nom, c'est-à-dire

let externalCalls = [call1()];
if (someCondition1) {
  externalCalls.push(call2());
}
if (someCondition2) {
  externalCalls.push(call3());
}

Je connais call1 code> sera toujours là, mais je ne sais pas si call2 ou call3 sera là. Je voudrais donc définir le résultat const de l'appel wait Promise.all dynamiquement pour avoir les bonnes propriétés, est-ce possible? Ou suis-je coincé avec un tableau de résultats générique de longueur inconnue, puis dois-je inspecter chaque élément des résultats pour voir quel appel l'a produit?


8 commentaires

const [call1, ... rest] peut-être


const [call1, ... restCalls] ?


cela devrait juste fonctionner, mais il est possible que call2, call3 ne soit pas défini.


@ ᆼ ᆺ ᆼ Ouais, donc cela permet un nombre dynamique d'éléments après call1, mais pouvez-vous expliquer comment j'utiliserais ensuite le paramètre rest pour déterminer quels appels ont été effectués?


@George, malheureusement, cela ne fonctionne pas. Disons que j'ai fait call1 et call3, si le résultat const a été défini comme [call1, call2, call3] , le résultat de call3 est en fait dans la variable call2 , et < code> call3 n'est pas défini.


Ah je vois, si someCondition1 est faux, vous ne poussez rien, alors si someCondition2 est vrai, vous appuyez sur call3 (), donc vous devriez vous attendre à ce que call3 soit dans le deuxième élément du tableau retourné.


Merci @BrianPloetz pour avoir posé ces questions, c'est exactement ce à quoi je suis confronté.


J'ai posté le code ci-dessous, veuillez regarder


4 Réponses :


1
votes

il n'y a pas de moyen direct de connaître la source de la réponse de promise.all.

mais vous pouvez ajouter plus d'informations à la réponse de call1, call2, call3

afin que votre code modifié soit ressemble à ça:

 returnedData = { 
    'call1': { call1 related data},
    'call2': { call2 related data},
    'call3': { call3 related data},
}

et dans votre réponse promise.all, vous pouvez vérifier la source de chaque réponse renvoyée comme suit "

let returnedData = {};
Promise.all(externalCalls).then(allData => {
    for(let data of allData){
        returnedData[data.source] = data;
        console.log(returnedData);
    }
});


1 commentaires

Oui, je suis conscient de cette approche, mais ma question portait spécifiquement sur la possibilité de générer dynamiquement l'instruction de déstructuration. Merci!



1
votes

D'une part, vous savez déjà quels appels ont été .push () vers externalCalls , sur la base de someCondition1 , etc. Mais peut-être est-il préférable de construire externalCalls d'une manière différente pour qu'il ait toujours la même longueur:

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)


0 commentaires

1
votes

Si someCondition1 est faux, vous ne poussez rien, alors si someCondition2 est vrai, vous poussez call3 (), donc vous devriez vous attendre à ce que call3 soit dans le deuxième élément du tableau retourné. Par conséquent, à la place, vous pouvez simplement renvoyer undefined pour les appels qui n'ont aucune valeur, en conservant les appels dans le tableau ayant des index synchronisés.

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);


1 commentaires

Merci @George. Vous et ᆼ ᆺ ᆼ avez tous deux proposé la même approche, mais comme ils vous ont battu de 7 minutes, je vais accepter leur réponse, mais je les ai tous les deux votés. :)



0
votes

Mon 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 commentaires