Je suis un peu coincé sur la partie centrale de mon code. Je sais à quoi je veux que la fin et le début ressemblent, mais je n'arrive pas à remplir le vide.
J'appelle fetch sur 4 points de terminaison d'API et stocke les promesses dans une clé pertinente qui me dit ce qu'ils sont.
Ensuite, je passe en revue tous ceux qui utilisent une boucle for in , et je pousse toutes ces Promises dans un tableau afin que je puisse appeler Promise .all sur eux.
Après avoir enregistré avec succès le tableau dans la console, je vois maintenant que le tableau est rempli d'objets avec mes données. Cependant, je n'ai aucun moyen de dire quelles données appartiennent à quelle clé d'objet, comme dans l'objet d'origine .
Y a-t-il une meilleure façon de faire cela? Je sais pertinemment que je souhaite utiliser Promise.all ici dans ce code; c'est quelque chose sur lequel je ne veux pas bouger, car j'essaie de comprendre comment je peux rendre cela possible sans abandonner (j'y suis depuis quelques heures maintenant).
À la fin de mon code (c'est juste un pseudocode pour un exemple réel dans mon application React), je veux juste prendre l'objet final et le pousser dans state .
Toute aide est appréciée.
//imitating React State as an example
const state = {
iliakan: '',
remy: '',
jeresig: '',
}
//put all of the urls in an object with a key-pair value to describe the data
const githubAPI = {
iliakan: 'https://api.github.com/users/iliakan',
remy: 'https://api.github.com/users/remy',
jeresig: 'https://api.github.com/users/jeresig'
}
//create an empty object to assign promises to keys
const movieData = {};
const promiseArr = [];
//store promise into relevant key
for (const user in githubAPI) {
movieData[user] = fetch().then(res => res.json())
}
//now movieData has keys with values set to related Promises
console.log(movieData);
//loop through these promises, and put them in an Array for Promise.all
for (const userData in movieData) {
promiseArr.push(movieData[userData])
}
//Use Promise.all on all of those promises
Promise.all(promiseArr).then(responseArr => console.log(responseArr);
//this is where I am stuck. I now have an array of objects with all the correct data, but I don't know how to reassign them back to their original, matching key that they had in the movieData object!
//end goal is to have an object like this
//const movieData = {
// iliakan: {//object with data from api},
// remy: {//object with data from api},
// jeresig: {//object with data from api}
//}
//use the movieData to setState and update current component state
3 Réponses :
Essayez ce qui suit, qui crée un tableau de clés qui suivra l'ordre des promesses et vous permettra de savoir quel "utilisateur" est associé à chaque promesse. Vous pouvez ensuite définir correctement l'objet movieData.
const movieData = {};
// Added keyTracker array declaration here...
const promiseArr = [], keyTracker = [];
for (const user in githubAPI) {
movieData[user] = fetch().then(res => res.json())
}
console.log(movieData);
for (const user in movieData) {
// Track the order of the promises by saving the key in our keyTracker
keyTracker.push(user);
promiseArr.push(movieData[user]);
}
Promise.all(promiseArr).then(responseArr => console.log(responseArr));
// Now we have a lookup for the keys (keyTracker) that will allow us to
// set the movieData correctly.
keyTracker.forEach((key, idx) => {
movieData[key] = promiseArr[idx];
});
Une façon de faire cela, est de voir la "connexion entre une clé et une propriété" comme sa propre "chose" en programmation: une paire clé-valeur.
L'API javascript les appelle "entrées" et utilise un simple tableau de 2 éléments comme "chose": Vous pouvez passer d'un objet à des entrées avec Vous pouvez maintenant utiliser ce concept, et faire les promesses également des "entrées", le résultat et la clé combinée dans un tableau Lodash a même Vous pouvez utiliser ce concept d '"entrées" pour n'importe quel endroit où vous jonglez entre objets et tableaux. J'espère que je l'ai suffisamment bien expliqué, n'ayez pas peur de poser des questions dans les commentaires si je ne l'ai pas fait! ['clé', 'valeur'] serait clé: 'valeur' code>. Object.entries (the_object) .
Il renverra un tableau avec "entry-array" -s à l'intérieur: let promiseOfEntries = Promise.all(Object.entries(githubAPI).map((entry) => {
let [key, value] = entry;
return fetch().then(x => x.json()).then(result => {
// Important step here: We combine the result with the key,
// into a new [key, value] entry
return [key, result];
})
}
let promiseOfResults = promiseOfEntries.then(resultEntries => {
// From the "entries", we build an object again here
let results = {};
for (let [key, value] of resultEntries) {
results[key] = value;
}
return results;
});
promiseOfResults.then(results => {
// Do anything with results!
console.log('results:', results);
});
[clé, valeur] . De cette façon, vous pouvez reconstruire ultérieurement l'objet à partir des entrées du résultat Promise.all . const githubAPI = {
iliakan: 'https://api.github.com/users/iliakan',
remy: 'https://api.github.com/users/remy',
jeresig: 'https://api.github.com/users/jeresig'
}
let githubEntries = Object.entries(githubAPI)
// githubEntries = [
// ['iliakan', 'https://api.github.com/users/iliakan'],
// ['remy', 'https://api.github.com/users/remy'],
// ['jeresig', 'https://api.github.com/users/jeresig'],
// ]
_.fromPairs pour effectuer cette conversion de [[clé, valeur], [clé2, valeur2], ...] en {clé: valeur, clé2: valeur2} .
https://lodash.com/docs/4.17.11#fromPairs p >
J'ai en fait une question (je passe toujours en revue le code que vous avez écrit ligne par ligne); sur cette ligne retournez fetch (). then (x => x.json ()). then (result => {, je devrais remplir le fetch () comme fetch (value) , correct?
@PhillipChoi oui! Vous pouvez y remplir tous les arguments de récupération, car vous gardez le return [key, result]; pour garder le résultat et la clé connectés
Une telle approche créative qui n'aurait jamais croisé la mienne. Merci Michiel!
Il vous suffit de mapper les clés avec les indices de tableau correspondants. C'est tout ce qui vous manque:
const movieData = responseArr.reduce((mD, response, index) => ({ ...mD, [orderOfKeys[index]]: response }), {})
Voici une ligne pour remplacer la boucle for:
const orderOfKeys = [] // create a helper Array
for (const userData in movieData) {
promiseArr.push(movieData[userData])
orderOfKeys.push(userData) // Memoize the keys, now the index matches the proper key
}
//Use Promise.all on all of those promises
Promise.all(promiseArr).then(responseArr => {
const movieData = {}
for (let i = 0; i < responseArr.length; i++) {
movieData[orderOfKeys[i]] = responseArr[i]
}
console.log(movieData) // bingo
});
Je me repens dans la poussière et dans les cendres.