Ответ
Promise (Обещание) — это абстракция для работы с асинхронными операциями, представляющая собой контейнер для значения (или ошибки), которое будет доступно в будущем. Это альтернатива замыканиям (completion handlers) и Combine, популярная благодаря библиотекам вроде PromiseKit или Swift concurrency (async/await).
Основные состояния Promise:
- Pending (Ожидание): Исходное состояние, операция выполняется.
- Fulfilled (Выполнено): Операция завершилась успешно, и Promise содержит результат.
- Rejected (Отклонено): Операция завершилась с ошибкой.
Зачем использовать Promises?
- Избегание «адской пирамиды замыканий» (Callback Hell): Позволяют выстраивать асинхронные операции в цепочку.
- Четкая обработка ошибок: Ошибки можно перехватывать в конце цепочки.
- Улучшенная читаемость: Код выглядит почти как синхронный.
Пример с использованием PromiseKit:
import PromiseKit
// Функция, возвращающая Promise
func fetchUserProfile(from url: URL) -> Promise<UserProfile> {
return Promise { seal in // `seal` — это объект для завершения Promise
URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error {
seal.reject(error) // 1. Завершаем с ошибкой
return
}
guard let data = data else {
seal.reject(NetworkError.noData) // 1. Завершаем с кастомной ошибкой
return
}
do {
let profile = try JSONDecoder().decode(UserProfile.self, from: data)
seal.fulfill(profile) // 2. Завершаем успешно с результатом
} catch {
seal.reject(error) // 1. Завершаем с ошибкой декодирования
}
}.resume()
}
}
// Использование: цепочка асинхронных операций
firstly {
fetchUserProfile(from: userURL) // Загружаем профиль
}.then { profile in
cacheProfile(profile) // Кэшируем его (возвращает Promise<Void>)
}.then { _ in
updateUI(with: profile) // Обновляем интерфейс
}.catch { error in
// Единая точка обработки ЛЮБОЙ ошибки из всей цепочки
print("Ошибка в цепочке: (error)")
}.finally {
// Код, который выполнится в любом случае (успех или ошибка)
hideLoadingIndicator()
}
Связь с современным Swift:
Нативная поддержка асинхронности в Swift (async/await) решает те же проблемы, что и Promise. Библиотеки PromiseKit можно использовать совместно с async/await через методы .value.
// Использование Promise с async/await
func loadData() async {
do {
let profile = try await fetchUserProfile(from: url).value // Ожидание Promise
await updateUI(with: profile)
} catch {
print(error)
}
}