J'utilise Firebase natif de réaction pour enregistrer mes médias dans Firebase. J'ai un ensemble d'URL qui doivent être enregistrées dans la base de feu. Pour cela, j'utilise map () pour enregistrer un par un. Après avoir enregistré, je pousse l'URL de succès vers le tableau. J'ai besoin d'appeler une fonction avec ce tableau comme paramètre. Je dois donc appeler cette fonction une fois le tableau terminé. J'ai beaucoup cherché mais je n'ai pas trouvé une bonne explication pour cette tâche. Quelqu'un peut-il m'aider. Merci.
var mediaArray = []; //array of success callbacks values var completedMediaSurveysAnswers = [{}, {}, {}]; //object array of URLs and media types completedMediaSurveysAnswers.map((i) => { try { const storage = firebase.storage(); const mRef = storage.ref('portal').child('Survey/Image/user/' + uuidv4() + 'media'); mRef.putFile(i.urlPath, { contentType: i.mediaType }) .on('state_changed', snapshot => {}, err => { console.log('Failed to upload file to firebase storage') }, uploadedFile => { // Success this.setState({ mediaPath: uploadedFile.downloadURL }) mediaArray.push(this.state.mediaPath) }); } catch (error) { console.log(error) } }) //need to call this function after loop is done saveAnswers(mediaArray)
3 Réponses :
utiliser .map est bien, donc vous pouvez renvoyer un tableau de promesses que vous pouvez ensuite attendre pour leur résolution
dans ce cas, la valeur résolue dans Promise.all sera ce que vous poussaient dans un tableau ... c'est-à-dire this.state.mediaPath
var completedMediaSurveysAnswers = [{}, {}, {}]; //object array of URLs and media types var promises = completedMediaSurveysAnswers.map((i) => new Promise((resolve, reject) => { try { const storage = firebase.storage(); const mRef = storage.ref('portal').child('Survey/Image/user/' + uuidv4() + 'media'); mRef.putFile(i.urlPath, { contentType: i.mediaType }).on('state_changed', snapshot => {}, err => { console.log('Failed to upload file to firebase storage'); resolve(null); // so one failure doesn't stop the whole process }, uploadedFile => { // Success this.setState({ mediaPath: uploadedFile.downloadURL }) resolve(this.state.mediaPath) }); } catch (error) { console.log(error) resolve(null); // so one failure doesn't stop the whole process } })); //need to call this function after loop is done Promise.all(promises).then(mediaArray => { saveAnswers(mediaArray); });
Dans chaque itération, this.state.mediaPath devrait pousser dans le mediaArray, n'est-ce pas?
incorrect ... la promesse est résolue ... alors mediaArray
est un tableau résultant des promesses - voyez comment mediaArray
n'est pas déclaré nulle part comme une variable, c'est un argument du rappel .then
Cela signifie donc qu'à partir de la ligne résoudre (this.state.mediaPath) , il ajoutera une par une toutes les promesses, n'est-ce pas?
en effet, et le résultat du tableau sera dans le même ordre que completedMediaSurveysAnswers
- contrairement à votre code d'origine où cela n'était pas garanti
Maintenant je comprends :) merci pour votre réponse. Acclamations!!
Vérifiez simplement la longueur de votre tableau de carte et comparez-la avec la clé de la carte.
Utilisez async await
pour attendre le téléchargement du fichier
var mediaArray = []; //array of success callbacks values var completedMediaSurveysAnswers = [{}, {}, {}]; //object array of URLs and media types completedMediaSurveysAnswers.map(async (i, key) => { try { const storage = firebase.storage(); const mRef = storage.ref('portal').child('Survey/Image/user/' + uuidv4() + 'media'); await mRef.putFile(i.urlPath, { contentType: i.mediaType }) .on('state_changed', snapshot => {}, err => { console.log('Failed to upload file to firebase storage') }, uploadedFile => { // Success this.setState({ mediaPath: uploadedFile.downloadURL }) mediaArray.push(this.state.mediaPath) }); if( key == (completedMediaSurveysAnswers.length - 1 ) ){ saveAnswers(mediaArray) } } catch (error) { console.log(error) } })
Je n'ai pas testé async await
donc utilisez-le partout où il est défini.
Vous pouvez utiliser Promise ou async / await pour gérer toutes sortes de situations comme celle-ci:
var mediaArray = []; var completedMediaSurveysAnswers = [{}, {}, {}]; async function handleYourTask() { await completedMediaSurveysAnswers.map((i) => { try { const storage = firebase.storage(); const mRef = storage.ref('portal').child('Survey/Image/user/' + uuidv4() + 'media'); mRef.putFile(i.urlPath, { contentType: i.mediaType }) .on('state_changed', snapshot => {}, err => { console.log('Failed to upload file to firebase storage') }, uploadedFile => { // Success this.setState({ mediaPath: uploadedFile.downloadURL }) mediaArray.push(this.state.mediaPath) }); } catch (error) { console.log(error) } }) await saveAnswers(mediaArray); }
et ensuite vous pouvez appeler la fonction handleYourTask où vous voulez :)
p>
Merci pour votre réponse. Je vais essayer celui-ci aussi :)
N'utilisez pas
.map
pour une itération simple. Utilisez.forEach
pour cela. Le mappage est un processus qui transforme chaque entrée en une autre, de sorte que vous obtenez une copie 1: 1 d'un tableau avec tous les éléments transformés par l'opération de mappage.comme ci-dessus ... sauf si le but de faire un .map est de renvoyer un tableau de promesses que vous pouvez attendre
Alors que le commentaire de @VLAZ est correct,
.map ()
serait une option valide si elle est utilisée correctement. Donc, au lieu de pousser des éléments à la main dansmediaArray
, il devrait êtremediaArray = completedMediaSurveysAnswers.map (...)
(plus quelques ajustements dans le rappel). Mais cela n'aidera pas dans ce cas -> Comment puis-je renvoyer la réponse d'un appel asynchrone?@VLAZ merci. J'utiliserai forEach. Mais je ne sais pas comment utiliser await / async ou promesses dans ce cas :(
Eh bien, première étape, vous avez besoin de quelques promesses à attendre ... en avez-vous dans votre code? non, vous ne le faites pas - alors, vous devrez en faire: D