J'exécute une fonction qui doit pousser 16 objets dans la position i
d'un tableau multidimensionnel. Je suis capable de pousser toutes les données dans var = videoData
utilisant videoData.push(videoItem)
mais je dois me retrouver avec un tableau multidimensionnel où chaque tableau imbriqué contient 16 objets.
var videoData = [[vid01, vid02....vid16], [vid01, vid02... vid16]]
Je m'attends à finir avec ...
//variables videoData = [], countries = ["GB", "ES", "PT", "VN", "ID"], tags = ["?tags=english", "?tags=spanish", "?tags=portugues", "?tags=vietnam", "?tags=indonesia"] //function function runTask(){ for(var i = 0; i < countries.length; i++){ axios({ method: "get", url: api_url + tags[i], headers: { "Content-Type": "application/json" }, }) .then(function(response) { var sixteenVideos = response.data for(var x = 0; x < 16; x++){ var videoItem = { "keys": { video: "vid" + [x+1] }, "values": { url: sixteenVideos[x].slug, thumb: sixteenVideos[x].image, title: sixteenVideos[x].title, desc: sixteenVideos[x].description } } videoData[i].push([videoItem]); } console.log(videoData); }).catch(function(error) { console.log(error); }); } }
4 Réponses :
Vous souhaitez utiliser une boucle similaire à celle-ci pour créer votre tableau multidimensionnel
function runTask() { var videoData = []; for (var i = 0; i < 6; i++) { var country = "Country -" + i; var countryArray = []; for (var x = 0; x < 16; x++) { var videoItem = country + ", Video -" + x; countryArray.push(videoItem); } videoData.push(countryArray); } }
For
boucle For
fonctionne de manière synchrone, lors de l'exécution d'opérations asynchrones dans la boucle for
, au moment où les promesses sont résolues for
boucle terminée, son exécution. Ainsi, la valeur de i
aura la valeur de la dernière itération de boucle dans chaque promesse résolue.
Je ne pense pas que la boucle for
soit vraiment nécessaire ici, il peut être plus simple de créer une fonction qui prend une balise et renvoie une promesse qui se résout en un tableau de 16 éléments, cela peut ressembler à ceci:
var videoData = []; var countries = ["GB", "ES", "PT", "VN", "ID"]; var tags = ["?tags=english", "?tags=spanish", "?tags=portugues", "?tags=vietnam", "?tags=indonesia"]; var tasks = tags.map(runTask); Promise.all(tasks).then(result => { console.log(result) }); function runTask(tag) { return axios({ method: "get", url: api_url + tag, headers: { "Content-Type": "application/json" }, }).then((response) => response.data .slice(0, 16) .map((video, index) => ({ "keys": { video: "vid" + [index + 1] }, "values": { url: video.slug, thumb: video.image, title: video.title, desc: video.description } })) ).catch(err => { console.log(err) }) }
Il y a beaucoup de problèmes avec votre code actuel. Je vais partir de zéro dans l'espoir que vous puissiez voir une meilleure façon d'aborder cela. Premièrement, axios a de nombreuses fonctionnalités de bas niveau que vous ne devriez pas vous inquiéter à chaque fois que vous récupérez json. Commencez par quelque chose comme fetchJson
-
const apiUrl = "https://my.api/" const requests = [ { country: "GB", tags: "?tags=english" } , { country: "ES", tags: "?tags=spanish" } , { country: "PT", tags: "?tags=portugues" } , { country: "VN", tags: "?tags=vietnam" } , { country: "ID", tags: "?tags=indonesia" } ] const fetchJson = (url = "") => axios ( { method: "get" , url , headers: { "Content-Type": "application/json" } } ) .then(res => res.data) const fetchVideos = ({ country = "", tag = "" }) => fetchJson(apiUrl + tag) .then(apiVideos => apiVideos.map(videoFromApi)) .then(videos => ({ country, videos })) const videoFromApi = ( { slug = "" , image = "" , title = "" , description = "" } , id = 0 ) => Object.assign ( { keys: { video: `vid${id + 1}` } } , { values: { url: slug , thumb: image , title: title , desc: description } } ) // mocks const axios = async (req = {}) => ({ data: randomVideos(4) }) const randomVideos = (n = 0) => Array.from(Array(n), randomVideo) const randomVideo = (_, id) => ( { url: `videourl/${id}` , image: `images/v${id}.jpg` , title: `Video: ${id}` , description: `This is video ${1}.` } ) // run demo Promise .all(requests.map(fetchVideos)) .then(console.log, console.error) // [ { country: "GB", videos: [ v1, v2, v3, ... ] } // , { country: "ES", videos: [ v1, v2, v3, ... ] } // , { country: "PT", videos: [ v1, v2, v3, ... ] } // , { country: "VN", videos: [ v1, v2, v3, ... ] } // , { country: "IN", videos: [ v1, v2, v3, ... ] } // ]
Maintenant, lorsque nous écrivons fetchVideos
, nous pouvons compter sur fetchJson
et sauter directement dans ce que nous devons faire avec la réponse analysée -
const requests = [ { country: "GB", tags: "?tags=english" } , { country: "ES", tags: "?tags=spanish" } , { country: "PT", tags: "?tags=portugues" } , { country: "VN", tags: "?tags=vietnam" } , { country: "ID", tags: "?tags=indonesia" } ] Promise .all(requests.map(fetchVideos)) // fetchVideos for each request .then(console.log, console.error) // then log the output, or error if incurred // [ { country: "GB", videos: [ v1, v2, v3, ... ] } // , { country: "ES", videos: [ v1, v2, v3, ... ] } // , { country: "PT", videos: [ v1, v2, v3, ... ] } // , { country: "VN", videos: [ v1, v2, v3, ... ] } // , { country: "IN", videos: [ v1, v2, v3, ... ] } // ]
Au lieu de s'appuyer sur des tableaux séparés de countries
et de tags
, fetchVideo
prend une entrée d' objet telle que -
const videoFromApi = ( { slug = "" , image = "" , title = "" , description = "" } , id = 0 ) => Object.assign ( { keys: { video: `vid${id + 1}` } } , { values: { url: slug , thumb: image , title: title , desc: description } } )
Et il produira un objet tel que -
// { country: "GB", videos: [ v1, v2, v3, ... ] }
Cela évite d'avoir à utiliser des index bruts pour lier des valeurs entre elles. Et nous avons gardé fetchVideos
haut niveau en fonction d'une autre fonction videoFromApi
. Cette fonction convertira les données de réponse vidéo de l'API dans la forme souhaitée pour notre application -
fetchVideos({ country: "GB", tag: "?tags=english" }) .then(console.log, console.error)
Maintenant, pour lier tout cela, nous définissons un tableau de requests
et utilisons Promise.all
pour fetchVideos
des fetchVideos
pour chaque requête. NB, cela nous permet de savoir précisément quand toutes les récupérations d'API sont terminées afin que notre programme puisse passer à l'étape suivante -
const apiUrl = "https://my.api/" const fetchVideos = ({ country = "", tag = "" }) => fetchJson(apiUrl + tag) .then(apiVideos => apiVideos.map(videoFromApi)) // convert each video .then(videos => ({ country, videos })) // build response
Pour voir une démo fonctionnelle, développez l'extrait ci-dessous et exécutez-le. axios
a été randomVideos
avec randomVideos
afin que nous puissions simuler une requête d'API -
const fetchJson = (url = "") => axios ( { method: "get" , url , headers: { "Content-Type": "application/json" } } ) .then(res => res.data)
Eh bien, vous ne pouvez pas faire cela "videoData[i].push"
car la position sur le tableau n'existe pas. Vous pouvez résoudre ce problème en utilisant un tableau auxiliaire comme celui-ci:
for(var x = 0; x < 16; x++){ var videoItem = { "keys": { video: "vid" + [x+1] }, "values": { url: sixteenVideos[x].slug, thumb: sixteenVideos[x].image, title: sixteenVideos[x].title, desc: sixteenVideos[x].description } } videoDataAux.push([videoItem]); } videoData[i]=videoDataAux
et que:
videoData = [] videoDataAux = []
Quelle est la sortie de courant? Est-ce quelque chose comme
[vid01,[vid01...]...]
?Non, c'est des erreurs pour le moment. Il montre
TypeError: Cannot read property 'push' of undefined
Cela signifie que quel que soit le système
videoitem
, il n'est pas défini. Êtes-vous sûr de recevoir correctement les données? Qu'est-ce que vousconsole.log(response);
? Vous poussez également un tableau d'objets comme ça..push(videoItem);
simplement.push(videoItem);
.La réponse ci-dessous d'Alex Gray fonctionne :)
n'oubliez pas d'utiliser
const
,let
ouvar
lors de la déclaration de variables