web-dev-qa-db-fra.com

Est-il possible d'utiliser axios.all avec un then () pour chaque promesse?

J'ai un composant React qui déclenche un événement pour récupérer des données. Il en résulte un nombre dynamique d'appels de procédure stockés pour extraire des données, et les données de chaque appel sont stockées dans un emplacement totalement différent. Ensuite, je dois effectuer un nouveau rendu lorsque toutes les données sont reçues et disponibles. J'utilise des promesses avec axios.

Le nombre d'appels axios étant dynamique, je construis un tableau et l'insère dans axios.all comme suit:

let promises = [];

for (let i = 0; i < requests.length; i++) {
    promises.Push(axios.get(request[i].url, { params: {...} }));
}

axios.all(promises).then(/* use the data */);

Le problème est que chaque requête axios renvoie des données qui sont ajoutées à un objet à un endroit totalement différent. Comme je n'ai aucun moyen de les mettre tous à la bonne place dans une seule variable then (comment saurais-je quelle réponse se trouve à quel endroit?), J'ai essayé de faire quelque chose comme ceci:

let promises = [];

for (let i = 0; i < requests.length; i++) {
    promises.Push(
        axios.get(request[i].url, { params: {...} })
            .then(response => {myObject[request[i].saveLocation] = response.data;})
    );
}

axios.all(promises).then(/* use the data */);

Cependant, cela ne fonctionne pas comme prévu. La then après chaque get est exécutée, mais pas bien après la then attachée à axios.all. Évidemment, c'est un problème parce que mon code essaie d'utiliser les données avant qu'elles aient été enregistrées dans l'objet.

Existe-t-il un moyen d’avoir un appel then séparé pour chaque axios.get qui sera exécuté après la résolution de la promesse correspondante, puis d’avoir une then finale qui ne sera exécutée qu’après que toutes des promesses sont résolues, pour données maintenant que l'objet a été rempli?

9
nanoguy

D'accord, j'ai donc trouvé un moyen de faire ce dont j'avais besoin sans utiliser un then sur chaque get. Étant donné que les paramètres transmis à axios.get contiennent suffisamment d’informations pour déterminer l’emplacement de la sauvegarde, et puisque je peux lire les paramètres à partir de la réponse, je peux effectuer les opérations suivantes:

let promises = [];

for (let i = 0; i < requests.length; i++) {
    promises.Push(axios.get(request[i].url, { params: {...} }));
}

axios.all(promises)
    .then(axios.spread((...args) => {
        for (let i = 0; i < args.length; i++) {
            myObject[args[i].config.params.saveLocation] = args[i].data;
        }
    }))
    .then(/* use the data */);

Cela garantit que toutes les données sont reçues et enregistrées dans l'objet avant qu'il ne soit utilisé.

21
nanoguy

Si le comportement de votre deuxième tentative est effectivement le même, cela indiquerait que axios n'est pas conforme à la promesse/A +. La valeur de retour du rappel then doit être la valeur avec laquelle la promesse renvoyée par cette then est remplie. Puisque c'est la promesse que vous insérez dans le tableau, la valeur que axios.all renverrait pour cette promesse ne peut être connue qu'en exécutant d'abord les rappels then.

Si vous ne renvoyez pas de valeur explicitement dans le rappel then, cela n’affectera pas la règle ci-dessus: dans ce cas, la valeur renvoyée est undefined et c’est la valeur cette qui devrait être fournie par axios.all une fois que la promesse correspondante est résolu.

Voir notamment les règles 2.2.7, 2.2.7.1, 2.3.2.1, 2.3.2.2 dans les spécifications de Promise/A + ).

Je suggère donc d'utiliser plutôt une implémentation de promesse conforme à Promise/A +. Il existe plusieurs autres bibliothèques, comme par exemple request-promise .

Vous pouvez également utiliser l'implémentation ES6 Promise native et promisify la méthode http.request vous-même.

ES6 offre Promise.all qui garantit de fournir les valeurs résolues dans le même ordre que les promesses.

2
trincot

votre code initial pourrait fonctionner normalement comme prévu si vous transmettez les promesses à votre tableau joint avec leur fonction then

let promises = []; // array to hold all requests promises with their then
for (let i = 0; i < requests.length; i++) {
    // adding every request to the array
    promises.Push(
        axios.get(request[i].url, { params: { ...} })
            .then(response => { myObject[request[i].saveLocation] = response.data; })
    );
}
// Resolving requests with their callbacks before procedding to the last then callback
axios.all(promises).then(/* use the data */);
0
mohamed hussein