promises
TRANSCRIPT
PromisesМетод (GET запрос)
Promise Контейнер для записи результата метода (или ошибки)
Future (результат)
Объект, содержащий результат
PromisesМетод (GET запрос)
Promise Контейнер для записи результата метода (или ошибки)
Future (результат)
Получатель 2Получают значение только после выполнения promise
Получатель 1
Объект, содержащий результат
PromisesМетод (GET запрос)
Promise Контейнер для записи результата метода (или ошибки)
Future (результат)
Получатель 2Получают значение только после выполнения promise
Получатель 1
В некоторых реализациях promise и future - единая сущность
Объект, содержащий результат
Цепочка promises
RecordPromise
ExportPromise
UploadPromise
Показываем пользователю, что все
загрузилось
• future - объект, содержащий результат
• promise - контейнер/средство для записи или передачи результата
• future - объект, содержащий результат
• promise выполняется только один раз
• promise - контейнер/средство для записи или передачи результата
• future - объект, содержащий результат
• promise выполняется только один раз
• future и promise часто представляют единую сущность (Javascript и PromiseKit в Swift)
• promise - контейнер/средство для записи или передачи результата
Состояния promise
• выполнено (fulfilled)
• ошибка в процессе выполнения (rejected)
• в процессе выполнения (pending)
Зачем нужны promises?
• Удобно создавать цепочки асинхронных операций
• Декларативное описание проблемы (что надо сделать, а не как это сделать)
Зачем нужны promises?
• Удобно создавать цепочки асинхронных операций
• Декларативное описание проблемы (что надо сделать, а не как это сделать)
• Легко обрабатывать ошибки
func getAnImageFromServer(url : NSURL) -> Future<UIImage> { let promise = Promise<UIImage>()
dispatch_async(...) { // загружаем картинку... let image = UIImage() promise.completeWithSuccess(image) } return promise.future }
Краткая иллюстрация
Библиотеки
• PromiseKit (Swift + ObjC) - 5714
• BrightFutures (Swift) - 1156
• FutureKit (Swift) - 458
Cтандарт Promises/A+ (Javascript)
• 3 состояния и логика перехода между ними
• логика поведения then
Cтандарт Promises/A+ (Javascript)
• 3 состояния и логика перехода между ними
• логика поведения then• логика разрешения
последующих promises
Создание Promise<T>public init(@noescape resolvers: (fulfill: (T) -> Void,
reject: (ErrorType) -> Void) throws -> Void)
Создание Promise<T>public init(@noescape resolvers: (fulfill: (T) -> Void,
reject: (ErrorType) -> Void) throws -> Void)
let promise = Promise<UIImage> { fulfill, reject in // some async download code here
fulfill(image) }
Свойства Promise• fulfilled (Bool)
• value (T?)
• pending (Bool)
• rejected (Bool)
• resolved (Bool)
Свойства Promise• fulfilled (Bool)
• value (T?)
• pending (Bool)
• rejected (Bool)
• resolved (Bool)
• error (ErrorType)
Основные операторы• then
public func then<U>(on q: dispatch_queue_t = PMKDefaultDispatchQueue(), _ body: (T) throws -> U) -> Promise<U>
Основные операторы• always
public func always(on q: dispatch_queue_t = PMKDefaultDispatchQueue(), _ body: () -> Void) -> Promise
Основные операторы• recover
public func recover(on q: dispatch_queue_t = PMKDefaultDispatchQueue(), _ body: (ErrorType) throws -> Promise) -> Promise
Основные операторы• error
func error(policy policy: ErrorPolicy = .AllErrorsExceptCancellation, _ body: (ErrorType) -> Void)
Примерfirstly { UIApplication.sharedApplication() .networkActivityIndicatorVisible = true }.then { _ -> Promise in let locater = CLLocationManager.promise() return when(locater)
}.then { location -> Void in //…
}.always { UIApplication.sharedApplication() .networkActivityIndicatorVisible = false
}.error { error in //…
}
Promises+Delegates• Создаем tuple
let (playerPromise, playerFulfill, playerReject) = Promise<Void>.pendingPromise()
Promises+Delegates• Создаем tuple
let (playerPromise, playerFulfill, playerReject) = Promise<Void>.pendingPromise()
• Возвращаем playerPromise
Promises+Delegates• Создаем tuple
let (playerPromise, playerFulfill, playerReject) = Promise<Void>.pendingPromise()
• Возвращаем playerPromise
• В методе делегата вызываем playerFulfillfunc audioPlayerDidFinishPlaying(player: AVAudioPlayer, successfully flag: Bool) { playerFulfill() }
=> сохранение на сервер
Нажата кнопка «Сохранить»=> проигрывание 4х квадратов=> преобразование файла
Use case No 2
=> сохранение на сервер
Нажата кнопка «Сохранить»=> проигрывание 4х квадратов=> преобразование файла
Use case No 2
Use case No 2
func didTapRecordButton() { sampler.recordSound().then { data in self.networkClient.uploadFileWithData(data, andName: DADefaultRecordingName) }.error { error in // Обработка ошибки } }
• на уровне ViewModel
Use case No 2
func recordFrom(start: Promise<Void>, until finish: Promise<Void>) -> Promise<NSData> { return when(start) .then(startRecording) .then { when(finish) } .then(stopRecordingAndExtractAudioFile) .then(export) }
• на уровне сервиса AudioEngine
Нажата кнопка «Проиграть»=> загрузка случайного бита=> остановка секвенсора=> проигрывание бита=> запуск секвенсора
Use case No 3
Нажата кнопка «Проиграть»=> загрузка случайного бита=> остановка секвенсора=> проигрывание бита=> запуск секвенсора
Use case No 3
Use case No 3
• на уровне ViewModel
func didTapPlayRandomFileButton() { networkClient.downloadRandomFile() .then(sampler.playFileFromNSData) }
Use case No 3
• на уровне сервиса NetworkClient
func downloadRandomFile() -> Promise<NSData> { return firstly(self.allPFObjectsFromServer) .then(self.downloadRandomFileFromPFObjects) }
Use case No 3
• на уровне сервиса AudioEngine
func playFileFromNSData(data: NSData) -> Promise<Void> { return Promise { fulfill, reject in self.avAudioPlayer = try AVAudioPlayer(data: data) self.avAudioPlayer.delegate = self self.avAudioPlayer.prepareToPlay() self.avAudioPlayer.play() fulfill() }.then { (self.playerPromise, self.playerFulfill, self.playerReject) = Promise<Void>.pendingPromise() return self.playerPromise }
Когда/где стоит использовать promises?
• Когда есть цепочка из нескольких асинхронных операций
• На уровне сервисов/интерактора
Когда/где стоит использовать promises?
• Когда есть цепочка из некоторых асинхронных операций
• На уровне сервисов/интерактора
• Когда требуется понять статус выполнения какой-либо операции
Когда/где стоит использовать promises?
• Когда есть цепочка из некоторых асинхронных операций
• На уровне сервисов/интерактора
• Когда требуется понять статус выполнения какой-либо операции
• Есть много различных ошибок
Когда/где не стоит использовать promises?
• Когда есть постоянно повторяющиеся действия (например, motion updates)
• На уровне вью (он будет знать о бизнес-логике)