← Назад к вопросам

Что такое Promise в Swift?

2.0 Middle🔥 181 комментариев
#Многопоточность и асинхронность#Язык Swift

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое Promise в Swift?

Promise (Обещание) — это паттерн программирования для работы с асинхронными операциями, представляющий будущий результат вычисления. В Swift Promise — это объект, который служит "промежуточным звеном" между инициатором асинхронной задачи и её конечным результатом, позволяя обрабатывать асинхронный код в более читаемом, линейном стиле без глубоко вложенных замыканий (так называемого "ада обратных вызовов").

Основная идея Promise

Promise инкапсулирует состояние асинхронной операции, которое может находиться в одном из трёх состояний:

  1. Pending (Ожидание) — начальное состояние, результат ещё не известен.
  2. Fulfilled (Выполнено) — операция успешно завершилась с результатом.
  3. Rejected (Отклонено) — операция завершилась с ошибкой.

Promise предоставляет методы для прикрепления обработчиков к этим состояниям, чаще всего через .then для успешного завершения и .catch для ошибок.

Пример реализации и использования Promise

Хотя в стандартной библиотеке Swift нет встроенного класса Promise, популярные сторонние библиотеки (например, PromiseKit) или собственная реализация выглядят так:

class Promise<T> {
    private var result: Result<T, Error>?
    private var handlers: [(Result<T, Error>) -> Void] = []
    
    func fulfill(_ value: T) {
        result = .success(value)
        handlers.forEach { $0(result!) }
    }
    
    func reject(_ error: Error) {
        result = .failure(error)
        handlers.forEach { $0(result!) }
    }
    
    func then<U>(_ handler: @escaping (T) -> U) -> Promise<U> {
        let newPromise = Promise<U>()
        addHandler { result in
            switch result {
            case .success(let value):
                let transformed = handler(value)
                newPromise.fulfill(transformed)
            case .failure(let error):
                newPromise.reject(error)
            }
        }
        return newPromise
    }
    
    func `catch`(_ handler: @escaping (Error) -> Void) {
        addHandler { result in
            if case .failure(let error) = result {
                handler(error)
            }
        }
    }
    
    private func addHandler(_ handler: @escaping (Result<T, Error>) -> Void) {
        if let result = result {
            handler(result)
        } else {
            handlers.append(handler)
        }
    }
}

Использование Promise для асинхронной загрузки данных:

func fetchUser(id: Int) -> Promise<User> {
    let promise = Promise<User>()
    NetworkService.loadUser(id: id) { result in
        switch result {
        case .success(let user):
            promise.fulfill(user)
        case .failure(let error):
            promise.reject(error)
        }
    }
    return promise
}

// Читаемый цепочный вызов
fetchUser(id: 42)
    .then { user in
        print("Пользователь получен: \(user.name)")
        return user.fetchAvatar() // Возвращает Promise<UIImage>
    }
    .then { avatar in
        imageView.image = avatar
    }
    .catch { error in
        print("Ошибка: \(error.localizedDescription)")
    }

Ключевые преимущества Promise

  • Избегание "адского коллбэка" (Callback Hell) — вместо вложенных замыканий получается плоская цепочка вызовов.
  • Чёткое разделение успеха и ошибки — обработчики .then и .catch разделены, что улучшает читаемость.
  • Композиция и цепочки — Promise можно легко комбинировать и преобразовывать с помощью .then, .map, .flatMap.
  • Управление состоянием — Promise гарантирует, что результат будет обработан только один раз (успех или ошибка).
  • Совместимость с существующим кодом — Promise легко оборачивает традиционные асинхронные функции с completion-блоками.

Сравнение с другими подходами

  • Completion handlers (замыкания) — более низкоуровневый подход, склонный к сложночитаемым вложениям.
  • Async/await (доступен с Swift 5.5) — более современная и элегантная альтернатива, где Promise не нужны, так как язык предоставляет встроенную поддержку асинхронности. Однако Promise остаются полезными для интеграции с legacy-кодом или в проектах, где ещё не используется Swift 5.5+.
// Тот же пример с async/await (Swift 5.5+)
func loadUserData() async {
    do {
        let user = try await NetworkService.loadUser(id: 42)
        print("Пользователь: \(user.name)")
        let avatar = try await user.fetchAvatar()
        imageView.image = avatar
    } catch {
        print("Ошибка: \(error)")
    }
}

Практическое применение

Promise особенно полезны в:

  • Сетевых запросах — последовательные или параллельные загрузки данных.
  • Анимациях — цепочки анимаций с обработкой завершения.
  • Работе с базами данных — асинхронные операции чтения/записи.
  • Композиции асинхронных операций — когда нужно выполнить несколько задач и обработать совокупный результат.

Promise в Swift, хоть и не являются частью стандартной библиотеки, остаются важным паттерном для структурирования асинхронного кода, особенно в проектах, которые ещё не перешли на использование async/await. Они существенно улучшают поддерживаемость и читаемость кода по сравнению с традиционными подходами с completion-блоками.

Что такое Promise в Swift? | PrepBro