【问题标题】:How to wait for Promise to resolve before returning a new Promise?如何在返回新的 Promise 之前等待 Promise 解决?
【发布时间】:2019-05-28 17:12:06
【问题描述】:

我正在构建一个用于创建零售标牌的 Web 应用程序。 Firestore 保存有关标志的信息,如果用户单击“删除所有标志”,我希望能够删除所有标志。然后将出现一个对话框,要求用户确认删除数据库中的所有标志。如果他们确认,则应从 Firestore 中删除所有标志。

每个标志的文档 ID 存储在一个名为 signIds 的数组中。我希望能够遍历 signIds 并从 Firestore 中的 signs 集合中删除每个文档。一旦所有的 Promise 都解决了,我想返回一个 Promise 并在 mounted() 的事件处理程序中解决它。

我尝试在代码的不同位置返回 Promise,但无济于事。我也尝试过使用asyncawait,但这似乎有同样的问题。

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

我希望新的 Promise 在 Firestore 的 Promise 解决后返回,但目前新的 Promise 在 for 循环完成后立即返回。

【问题讨论】:

    标签: javascript firebase vue.js


    【解决方案1】:

    您当前通过signIdsPromises 迭代没有与其他任何东西链接-.delete() 承诺目前没有在任何地方使用。最好将.map 每个id 转换为一个数组中的Promise,然后在该数组上使用Promise.all。如果在消费者中处理错误,则无需在 emptyQueuecatch 只是抛出一个新错误 - 相反,只需单独返回 Promise 链,并避免 explicit Promise construction anti-pattern

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

    如果任何一个.delete() 调用导致错误,该错误将渗透到您的

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

    部分自动通过Promise.all

    【讨论】:

    • 很好的答案,它完全按照你写的那样工作,完全没有错误!
    【解决方案2】:

    【讨论】:

      【解决方案3】:

      您应该可以使用batch 来执行此操作,代码应如下所示:

      // 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();
      

      【讨论】:

        猜你喜欢
        • 2016-10-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-05-09
        • 2017-04-02
        • 1970-01-01
        • 2020-12-02
        相关资源
        最近更新 更多