1
votes

Comment appeler une fonction après l'exécution de la boucle map ()

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)


5 commentaires

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 dans mediaArray , il devrait être mediaArray = 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


3 Réponses :


1
votes

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);
});


5 commentaires

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!!



0
votes

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.


0 commentaires

3
votes

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>


1 commentaires

Merci pour votre réponse. Je vais essayer celui-ci aussi :)