Как превратить функцию в асинхронную - PullRequest
0 голосов
/ 27 января 2020

Начну с того, что у меня практически нет опыта по созданию асин c функций, и после прочтения документации по нему я еще больше запутался.

Я использую vue. js в качестве фреймворка и мои методы делают вызовы в firebase.

Goal

Проблема в том, что при firebase при удалении документа он автоматически не удаляет все вложенные документы, вы должны сделать это вручную с помощью рекурсивных функций. Поэтому мне пришлось воссоздать функцию удаления для выполнения sh и сделать это, сделав миксин. Миксин теперь работает, однако, событие reload emit теперь срабатывает до завершения функции удаления, и в результате в DOM остается элемент-призрак.

Я хочу, чтобы $emit('reload') не срабатывал, пока все вызовы пожарная база в deleteProject() закончена.

Мой код

<script>
import { deleteProject } from '../../../mixins/deleteData'

export default {
  mixins: [deleteProject],
  props: ['yearId', 'projectId', 'project'],
  name: 'deleteProjectModal',
  data: () => ({
    dialog: false
  }),
  methods: {
    del () {
      // call deleteYear method from mixin
      this.deleteProject(this.yearId, this.projectId)
      // emit reload signal for database relaod
      this.$emit('reload')
      // close modal
      this.dialog = false
    }
  }
}
</script>
import firebase from '@/firebase/init'

export const deleteProject = {
  methods: {
    deleteProject (yearId, projectId) {
      // delete project, all documents in the images subcollection of the project, and all stored images
      firebase.firestore().collection('years').doc(yearId).collection('projects').doc(projectId).get()
        .then((doc) => {
          // delete thumbnail
          firebase.storage().ref(doc.data().thumbFullPath).delete()
          // delete project document
          firebase.firestore().collection('years').doc(yearId).collection('projects').doc(projectId).delete()
          firebase.firestore().collection('years').doc(yearId).collection('projects').doc(projectId).collection('images').get()
            .then((querySnapshot) => {
              querySnapshot.forEach((doc) => {
                // delete gallery image
                this.imagePaths.append(doc.data().fullPath)
                // delete reference document for gallery image
                doc.ref.delete()
              })
            })
        })
    }
  }
}

Что я пробовал

Я предполагаю, что решение будет вращаться вокруг превращения deleteProject() в асинхронную c функцию и вызова deleteProject().then($emit('reload')). Однако я не смог понять, как это сделать.

Редактировать

В соответствии с запросом reload вызывает следующую функцию:

import firebase from '@/firebase/init'

export const loadGallery = {
  data: () => ({
    years: []
  }),
  methods: {
    loadProjects () {
      var years = []
      var temp = []
      firebase.firestore().collection('years').orderBy('year', 'desc').onSnapshot((querySnapshot) => {
        querySnapshot.forEach((year) => {
          firebase.firestore().collection('years').doc(year.id).collection('projects').get().then((querySnapshot) => {
            querySnapshot.forEach((project) => {
              var objectMicro = { title: project.data().title, thumbUrl: project.data().thumbUrl, route: project.data().route, id: project.id }
              temp.push(objectMicro)
            })
          }).then(() => {
            var objectMacro = { year: year.data().year, id: year.id, projects: temp }
            years.push(objectMacro)
            temp = []
          })
        })
      })
      this.years = years
    }
  }
}

Ответы [ 2 ]

2 голосов
/ 27 января 2020

Вам просто нужно вернуть foremost .then() в цепочке Promise этого deleteProject метода, и любой последующий вызов сможет его забрать с этой точки.

deleteProject() {
  // Add a return keyword here, or assign the Promise to a variable and return it. 
  return firebase.firestore().collection('years').doc(yearId).collection('projects').doc(projectId).get()
        .then( /* removed for brevity */ )
}

Метод вызова,

methods: {
  del() {
    this.deleteProject(this.yearId, this.projectId).then(() => {
      this.$emit('reload')
    })
  }
}

Или сделать его "красивее" с ключевым словом async,

methods: {
  async del() {
    // You probably want to do try-catch here as well.
    await this.deleteProject(this.yearId, this.projectId);

    this.$emit('reload');
  }
}
1 голос
/ 29 января 2020

Вы выполняете несколько асинхронных операций Firebase в вашем методе deleteProject (вызов Firestore get(), Firestore delete(), облачное хранилище delete(), ...) но вы неправильно соединяете в цепочку различные обещания, возвращаемые этими методами Firebase.

Вы должны связать эти Обещания с помощью метода then(), который «возвращает Обещание, которое допускает связывание методов».

Итак, следующее должно выполнить хитрость (однако, не проверено):

export const deleteProject = {
   methods: {     
      deleteProject (yearId, projectId) {
      // delete project, all documents in the images subcollection of the project, and all stored images
      return firebase.firestore().collection('years').doc(yearId).collection('projects').doc(projectId).get()
        .then((doc) => {
          // delete thumbnail
          return firebase.storage().ref(doc.data().thumbFullPath).delete()
        })
       .then(() => {
          return firebase.firestore().collection('years').doc(yearId).collection('projects').doc(projectId).delete();
       })
       .then(() => {
          return firebase.firestore().collection('years').doc(yearId).collection('projects').doc(projectId).collection('images').get()
       })
       .then((querySnapshot) => {
          const promises = [];
          querySnapshot.forEach((doc) => {
            // delete gallery image
            this.imagePaths.append(doc.data().fullPath)
            // delete reference document for gallery image
            promises.push(doc.ref.delete());
          })
          return Promise.all(promises);
       })
      }
  }
}

И поскольку этот deleteProject() метод теперь асинхронный, вам нужно вызвать его следующим образом в своем миксине:

  methods: {
    del () {
      // call deleteYear method from mixin
      this.deleteProject(this.yearId, this.projectId)
      .then(() => {
         // emit reload signal for database relaod
         this.$emit('reload')
         // close modal
         this.dialog = false
      })
    }
  }

Примечание что мы используем Promise.all() для параллельного выполнения всех вызовов метода delete() в forEach(). Метод Promise.all() возвращает одно Обещание, которое выполняется, когда все обещания, переданные как итеративные (т. Е. Массив promises), были выполнены.

...