до сих пор не могу понять, как заказать асинхронные задачи для удаления пользователя
Поэтому я пытаюсь обеспечить выполнение набора асинхронных задач в определенном порядке при удалении пользователя.
Итак, что я хочу:
- Проверьте, добавил ли пользователь гостей к своей покупке
- если у пользователя нет гостей или каких-либо покупок, вернитесь из функции и продолжите процесс удаления (пункт 6)
- если у пользователя есть гости для каких-либо покупок, удалите каждого гостя
- как только все гости будут удалены, продолжайте и удаляйте все сделанные ими покупки
- как только все сделанные покупки будут удалены, удалите самого пользователя из Firestore.
- Через 2 секунды после этого я удаляю пользователя из аутентификации firebase, чтобы убедиться, что нет сбоев при попытке удалить документы с пустым пользователем
- затем я просто перехожу в главное меню
Итак, я пытаюсь добиться этого с помощью этого блока кода в моей функции:
let deleteAction = UIAlertAction(title: "Delete", style: .destructive) { (deletion) in
let semaphore = DispatchSemaphore(value: 0)
self.deleteButton.isHidden = true
self.loadingToDelete.alpha = 1
self.loadingToDelete.startAnimating()
DispatchQueue.global(qos: .background).async {
self.db.collection("student_users/\(user.uid)/events_bought").getDocuments { (querySnapshot, error) in
guard error == nil else {
print("The docs couldn't be retrieved for deletion.")
return
}
guard querySnapshot?.isEmpty == false else {
print("The user being deleted has no events purchased.")
return
}
for document in querySnapshot!.documents {
let docID = document.documentID
self.db.collection("student_users/\(user.uid)/events_bought/\(docID)/guests").getDocuments { (querySnap, error) in
guard querySnap?.isEmpty == false else {
print("The user being deleted has no guests with his purchases.")
return
}
for doc in querySnap!.documents {
let guest = doc.documentID
self.db.document("student_users/\(user.uid)/events_bought/\(docID)/guests/\(guest)").delete { (error) in
guard error == nil else {
print("Error deleting guests while deleting user.")
return
}
print("Guests deleted while deleting user!")
semaphore.signal()
}
semaphore.wait()
}
}
}
}
self.db.collection("student_users/\(user.uid)/events_bought").getDocuments { (querySnapshot, error) in
guard error == nil else {
print("There was an error retrieving docs for user deletion.")
return
}
guard querySnapshot?.isEmpty == false else {
return
}
for document in querySnapshot!.documents {
let docID = document.documentID
self.db.document("student_users/\(user.uid)/events_bought/\(docID)").delete { (err) in
guard err == nil else {
print("There was an error deleting the the purchased events for the user being deleted.")
return
}
print("Purchases have been deleted for deleted user!")
semaphore.signal()
}
semaphore.wait()
}
}
self.db.document("student_users/\(user.uid)").delete(completion: { (error) in
guard error == nil else {
print("There was an error deleting the user document.")
return
}
print("User doc deleted!")
semaphore.signal()
})
semaphore.wait()
}
DispatchQueue.main.asyncAfter(deadline: .now()+1.5) {
user.delete(completion: { (error) in
guard error == nil else {
print("There was an error deleting user from the system.")
return
}
print("User Deleted.")
})
}
self.loadingToDelete.stopAnimating()
self.performSegue(withIdentifier: Constants.Segues.studentUserDeletedAccount, sender: self)
}
Последние пару часов я пытался поиграться с ним и внедрить его в свой код, но он просто не делает того, что я ожидаю. Я бы прочитал статьи и примеры
DispatchSemaphore()
онлайн, но сценарии не совсем такие же, как у меня, в том, что касается того, что я конкретно хочу делать.
Когда это предупреждающее действие запускается при нажатии, ничего не печатается, и оно просто заканчивается вечно, пользователь не удаляется из Firebase Auth, и в базе данных Firestore все еще есть оставшиеся данные, например:
Я просто в основном хочу выяснить, как лучше всего упорядочить эти асинхронные задачи в упорядоченном списке выше и получить чистое удаление пользователя без остатка в базе данных. Заранее спасибо.
1 ответ
Вы должны справиться с этим с помощью облачной функции Firebase, которая имеет несколько способов реагирования на запросы клиентов и изменения базы данных. Это требует выставления счетов и переноса вашего кода на javascript с помощью узла v10, что довольно просто из-за согласованных методов firebase на большинстве языков.
Функция Firebase
Два популярных метода - это просто импорт модуля облачных функций firebase в ваше приложение или вызов запроса через https, каждый из которых имеет свои собственные точки входа с плюсами и минусами, которые стоит прочитать.
- https://firebase.google.com/docs/functions/callable
- https://firebase.google.com/docs/functions/http-events
Оттуда вы должны удалить основные файлы, которые немедленно повлияют на пользователя, а затем обновить клиент по их результатам, прежде чем приступить к очистке остаточных файлов.
Триггер Firestore
Альтернативой, которая столь же надежна и более управляема от потенциальных злоупотреблений, является запуск триггера на основе удаления документа, вы можете использовать его, чтобы затем инициировать удаление и очистку других документов.
Вы можете прочитать о них ниже, и он может содержать принципиально одинаковую логику в обеих ситуациях, но этот вариант не требует громоздкого модуля функций firebase.
https://firebase.google.com/docs/functions/firestore-events#function_triggers
Обновление: асинхронный
Асинхронные методы - это просто функции, помеченные как
async
которые позволяют задачам работать без блокирующей структуры, это позволяет запускать несколько задач независимо от другой. Однако, чтобы приостановить код и дождаться выполнения каких-либо действий, вы можете добавить флаг
function resolveAfter2Seconds() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved');
}, 2000);
});
}
async function asyncCall() {
console.log('calling');
const result = await resolveAfter2Seconds();
console.log(result);
// expected output: "resolved"
}
asyncCall();
ссылка: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
Обновление: обещания
Обещания работают так же, как асинхронные функции, и выполняются независимо от родительской функции, и сами могут быть помечены
await
если нужно.
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('foo');
}, 300);
});
myPromise
.then(handleResolvedA, handleRejectedA)
.then(handleResolvedB, handleRejectedB)
.then(handleResolvedC, handleRejectedC);
ссылка: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise