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?
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é.
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.
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 */);