promises

80
Promises

Upload: rambler-ios

Post on 21-Feb-2017

109 views

Category:

Technology


0 download

TRANSCRIPT

Promises

Promises

• Что это?

Promises

• Что это?

• Зачем они нужны?

PromisesМетод (GET запрос)

PromisesМетод (GET запрос)

Promise Контейнер для записи результата метода (или ошибки)

PromisesМетод (GET запрос)

Promise Контейнер для записи результата метода (или ошибки)

Future (результат)

Объект, содержащий результат

PromisesМетод (GET запрос)

Promise Контейнер для записи результата метода (или ошибки)

Future (результат)

Получатель 2Получают значение только после выполнения promise

Получатель 1

Объект, содержащий результат

PromisesМетод (GET запрос)

Promise Контейнер для записи результата метода (или ошибки)

Future (результат)

Получатель 2Получают значение только после выполнения promise

Получатель 1

В некоторых реализациях promise и future - единая сущность

Объект, содержащий результат

Цепочка promises

RecordPromise

Цепочка promises

RecordPromise

ExportPromise

Цепочка promises

RecordPromise

ExportPromise

UploadPromise

Цепочка promises

RecordPromise

ExportPromise

UploadPromise

Показываем пользователю, что все

загрузилось

• promise - контейнер/средство для записи или передачи результата

• future - объект, содержащий результат

• promise - контейнер/средство для записи или передачи результата

• future - объект, содержащий результат

• promise выполняется только один раз

• promise - контейнер/средство для записи или передачи результата

• future - объект, содержащий результат

• promise выполняется только один раз

• future и promise часто представляют единую сущность (Javascript и PromiseKit в Swift)

• promise - контейнер/средство для записи или передачи результата

Состояния promise

• выполнено (fulfilled)

Состояния promise

• выполнено (fulfilled)

• в процессе выполнения (pending)

Состояния promise

• выполнено (fulfilled)

• ошибка в процессе выполнения (rejected)

• в процессе выполнения (pending)

Зачем нужны promises?

• Декларативное описание проблемы (что надо сделать, а не как это сделать)

Зачем нужны promises?

• Удобно создавать цепочки асинхронных операций

• Декларативное описание проблемы (что надо сделать, а не как это сделать)

Зачем нужны promises?

• Удобно создавать цепочки асинхронных операций

• Декларативное описание проблемы (что надо сделать, а не как это сделать)

• Легко обрабатывать ошибки

Краткая иллюстрация

func getAnImageFromServer(url : NSURL) -> Future<UIImage> { let promise = Promise<UIImage>()

dispatch_async(...) { // загружаем картинку... let image = UIImage() promise.completeWithSuccess(image) } return promise.future }

Краткая иллюстрация

Использование promises в iOS

Библиотеки

• PromiseKit (Swift + ObjC) - 5714

Библиотеки

• PromiseKit (Swift + ObjC) - 5714

• BrightFutures (Swift) - 1156

Библиотеки

• PromiseKit (Swift + ObjC) - 5714

• BrightFutures (Swift) - 1156

• FutureKit (Swift) - 458

PromiseKit

PromiseKit

Логика работы - стандарт Promises/A+

Cтандарт Promises/A+ (Javascript)

• 3 состояния и логика перехода между ними

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)

Свойства Promise• fulfilled (Bool)• pending (Bool)

Свойства Promise• fulfilled (Bool)• pending (Bool)• resolved (Bool)

Свойства Promise• fulfilled (Bool)• pending (Bool)

• rejected (Bool)

• resolved (Bool)

Свойства Promise• fulfilled (Bool)

• value (T?)

• pending (Bool)

• rejected (Bool)

• resolved (Bool)

Свойства Promise• fulfilled (Bool)

• value (T?)

• pending (Bool)

• rejected (Bool)

• resolved (Bool)

• error (ErrorType)

Основные операторы• when

public func when<T>(promises: Promise<T>...) -> Promise<[T]>

Основные операторы• 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)

Основные операторы• race

public func race<T>(promises: Promise<T>...) -> Promise<T>

Основные операторы• after

public func after(delay: NSTimeInterval) -> Promise<Void>

Категории

• MapKit

Категории

• MapKit

• AVAudioSession

Категории

• MapKit

• AVAudioSession

• NSURLSession

Категории

• MapKit

• AVAudioSession

• NSURLSession• и многие другие библиотеки

Пример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() }

Примеры из практики (драм - машина)

Изменение положения девайса

Use case No 1

=> изменение бита

Изменение положения девайса

Use case No 1

=> изменение бита

=> сохранение на сервер

Нажата кнопка «Сохранить»=> проигрывание 4х квадратов=> преобразование файла

Use case No 2

=> сохранение на сервер

Нажата кнопка «Сохранить»=> проигрывание 4х квадратов=> преобразование файла

Use case No 2

Use case No 2

• на уровне ViewModel

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

• на уровне сервиса AudioEngine

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

Use case No 3

• на уровне ViewModel

func didTapPlayRandomFileButton() { networkClient.downloadRandomFile() .then(sampler.playFileFromNSData) }

Use case No 3

• на уровне сервиса NetworkClient

Use case No 3

• на уровне сервиса NetworkClient

func downloadRandomFile() -> Promise<NSData> { return firstly(self.allPFObjectsFromServer) .then(self.downloadRandomFileFromPFObjects) }

Use case No 3

• на уровне сервиса AudioEngine

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?

• Когда есть цепочка из некоторых асинхронных операций

• На уровне сервисов/интерактора

• Когда требуется понять статус выполнения какой-либо операции

• Есть много различных ошибок

Когда/где не стоит использовать promises?

• На уровне вью (он будет знать о бизнес-логике)

Когда/где не стоит использовать promises?

• Когда есть постоянно повторяющиеся действия (например, motion updates)

• На уровне вью (он будет знать о бизнес-логике)

Когда/где не стоит использовать promises?

• Когда есть постоянно повторяющиеся действия (например, motion updates)

• На уровне вью (он будет знать о бизнес-логике)

• Когда цепочки операций достаточно маленькие