3
votes

Comment attendre la résolution de la promesse avant de renvoyer une nouvelle promesse?

Je suis en train de créer une application Web pour créer une signalétique commerciale. Firestore contient des informations sur les panneaux et je souhaite pouvoir supprimer tous les panneaux si un utilisateur clique sur «Supprimer tous les panneaux». Une boîte de dialogue apparaîtra alors qui demandera à l'utilisateur de confirmer la suppression de tous les signes de la base de données. S'ils le confirment, alors tous les signes doivent alors être supprimés de Firestore.

L'ID de document de chaque signe est stocké dans un tableau appelé signIds . Je veux pouvoir parcourir signIds et supprimer chaque document de la collection signes dans Firestore. Une fois que toutes les promesses ont été résolues, je veux retourner une promesse et la résoudre dans le gestionnaire d'événements dans mounted() .

J'ai essayé de renvoyer une promesse à différents endroits dans le code, en vain. J'ai également essayé d'utiliser async et await mais cela semblait avoir le même problème.

data() {
        return {
            signIds: [],
        }
},
methods: {
    showModal(message, type) {
        this.$root.$emit('openModal', {
            closed: false,
            text: message,
            type: type
        })
    },
    emptyQueue() {
        let self = this;
        let deleted = 0;

        for (let id of self.signIds) {
            database.collection("signs").doc(id).delete()
                .then(() => {
                    console.log("Document successfully deleted!");
                    deleted++;
                }).catch((error) => {
                    console.error("Error removing document: ", error);
                });
        }

        // Once all signs are deleted, return new Promise
        return new Promise((resolve, reject) => {
            return (deleted === self.signIds.length) ? resolve() : reject(new Error('An error occurred while deleting signs.'));
        });
    }      
},
created() {
        // Get and store the document id for each sign
        database.collection("signs").get()
            .then(snapshot => {
                snapshot.forEach(doc => {
                    this.signIds.push(doc.id);
                })
            });
    },
mounted() {
        // When the user clicks 'OK' on the dialog, delete all signs from the database
        this.emptyQueue()
            .then(() => {
                setTimeout(function() {
                    self.showModal('All signs were successfully removed.', 'success');
                }, 300);
            }).catch(() => {
                setTimeout(function() {
                    self.showModal('An error has occurred. Some signs were not removed.', 'error');
                }, 300);
            })
        }

Je m'attends à ce que la nouvelle promesse revienne après la résolution des promesses de Firestore, mais actuellement la nouvelle promesse est retournée immédiatement après la fin de la boucle for .


0 commentaires

3 Réponses :


4
votes

Votre itération actuelle via les promesses de signIds n'est enchaînée avec rien d'autre - les promesses .delete () ne sont pas utilisé n'importe où pour le moment. Il serait préférable de .map chaque id vers une Promise dans un tableau, puis d'utiliser Promise.all sur ce tableau. Si des erreurs sont gérées dans le consommateur, il n'est pas nécessaire de attraper dans emptyQueue juste pour lancer une nouvelle erreur - à la place, renvoyez simplement la chaîne Promise seule et évitez le anti-modèle de construction de promesse explicite a>:

this.emptyQueue()
  // ...
  .catch(() => {
    ...
  });

Si l'un des appels .delete () aboutit à une erreur, cette erreur se répercutera jusqu'à votre

emptyQueue() {
  return Promise.all(
    this.signIds.map(id => (
      database.collection("signs").doc(id).delete()
    ))
  );
}

section automatiquement via le Promise.all.


1 commentaires

Excellente réponse, cela a fonctionné exactement comme vous l'avez écrit sans aucune erreur!



1
votes

L'utilisation du batch d'écriture peut répondre à vos besoins https: // firebase.google.com/docs/reference/js/firebase.firestore.WriteBatch


0 commentaires

1
votes

Vous devriez pouvoir le faire en utilisant batch , avec un code qui devrait ressembler à ceci:

// start a batch
var batch = database.batch();

for (let id of self.signIds) {
  // for each, add a delete operation to the batch
  batch.delete(database.collection("signs").doc(id));
}

// Commit the batch
batch.commit();


0 commentaires