Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Promise, promise

Promise, promise

Vlad Vysotsky - mobile developer at Ekreative/Kidslox startup
У кожного в житті настає момент, коли треба виконати якісь складні обрахунки в бекграундному потоці, писати купу умов, ще й колбеків в колбеках і потім все це дебажити. Той момент, коли купа задач залежить одна від одної і ти не розумієш, як то все гарно й адекватно написати. А ще й проект треба зарелізити вже вчора, тому і розбиратись з якимись реактивними функціональними приблудами та, тим більше, приплітати їх до свого проекту часу і сенсу немає? — Не біда. Все вже реалізовано до нас, ми лише розглянемо як використовувати модні зараз Promise на вашому проекті (iOS, Android). Розглянемо основну теорію, подивимось, куди і як то все рухається.

Avatar for GDG Cherkasy

GDG Cherkasy

February 24, 2017
Tweet

More Decks by GDG Cherkasy

Other Decks in Programming

Transcript

  1. Працюю Android, iOS developer Балуюсь Groovy on grails, Angular Kotlin&Swift

    lover email: [email protected] gh: www.github.com/vysotsky fb: https://www.facebook.com/wolltone Мене звати Влад
  2. Hey mama, look at me I'm on my way to

    the promised land, whoo! I'm on the highway to callback hell -Brian Johnson, AC/DC
  3. Що таке Promise? Основна ідея полягає в тому, що Promise

    - результат асинхронної операції. Він може бути в одному з трьох різних станів: • pending - початковий стан; • fulfilled - стан, що представляє успішну операцію; • rejected - стан, що представляє невдалу операцію. Після виконання Promise залишиться незмінним.
  4. Rx або Promise Promise - “async single value” - task

    parallelization model Rx - “async list of values” - reactive extension model
  5. required public init(resolvers: (_ fulfill: @escaping (T) -> Void, _

    reject: @escaping (Error) -> Void) throws -> Void)
  6. let foo = Promise<UIImage> { fulfill, reject in guard let

    image = try downloadImage() else { return reject(ImageError.noImage) } fulfill(image) }
  7. let foo = Promise<UIImage> { fulfill, reject in guard let

    image = try downloadImage() else { return reject(ImageError.noImage) } fulfill(image) }
  8. firstly { UIApplication.shared.isNetworkActivityIndicatorVisible = true return when(fulfilled: URLSession.dataTask(with: url).asImage(), CLLocationManager.promise())

    }.then { image, location in self.imageView.image = image self.label.text = "\(location)" }.always { UIApplication.shared.isNetworkActivityIndicatorVisible = false }.catch { error in UIAlertView(with: error.localizedDescription).show() }
  9. func fetchInBackground(logins: [String]) -> Promise<UIBackgroundFetchResult> { return race(after(interval: 20).then {

    throw CustomError.error }, when(fulfilled: logins.map(downloadUser)) .then { users -> UIImage? in return try self.makeSomething(with: users) }.then { _ -> Void in AppDelegate.coreDataProvider.saveContext() }.then { return Promise(value: .newData) }.recover { error in Analytics.log(error) return Promise(value: .failed) }) }
  10. func login() -> Promise<User> { UIApplication.shared.isNetworkActivityIndicatorVisible = true return firstly

    { Alamofire.request(url, method: .get).responseData() }.then(on: DispatchQueue.global()) { data in convertToUser(data) }.always { UIApplication.shared.isNetworkActivityIndicatorVisible = false } }
  11. final TaskCompletionSource<GenericObject> tcs = new TaskCompletionSource<>(); tcs.setResult(object); //it should be

    called inside the async block tcs.setError(e); //in case of error return tcs.getTask();
  12. saveAsync(obj).continueWith(new Continuation<ParseObject, Void>() { public Void then(Task<ParseObject> task) throws Exception

    { if (task.isCancelled()) { // the save was cancelled. } else if (task.isFaulted()) { // the save failed. Exception error = task.getError(); } else { ParseObject object = task.getResult(); } return null; } });
  13. loadUsersAsync(query).onSuccessTask(new Continuation<List<User>, Task<Something>>() { public Task<Something> then(Task<List<Users>> task) throws Exception

    { return makeSomethingAsync(task.getResult()); } }).onSuccessTask(new Continuation<Something, Task<SometingElse>>() { public Task<SometingElse> then(Task<Something> task) throws Exception { return makeSomethingElseAsync(task.getResult()); } }).onSuccess(new Continuation<SometingElse, Void>() { public Void then(Task<SometingElse> task) throws Exception { return null; } });
  14. loadUsersAsync(query).onSuccessTask(new Continuation<List<User>, Task<Something>>() { public Task<Something> then(Task<List<Users>> task) throws Exception

    { throw new RuntimeException("There was an error."); return makeSomethingAsync(task.getResult()); } }).onSuccessTask(new Continuation<Something, Task<SometingElse>>() { public Task<SometingElse> then(Task<Something> task) throws Exception { //skipped return makeSomethingElseAsync(task.getResult()); } }).continueWith(new Continuation<SometingElse, Void>() { public Void then(Task<SometingElse> task) throws Exception { //will be called return null; } });
  15. Task.call(new Callable<HttpResponse>() { @Override public HttpResponse call() throws Exception {

    return client.execute(request); } }, NETWORK_EXECUTOR).continueWithTask(new Continuation<HttpResponse, Task<byte[]>>() { @Override public Task<byte[]> then(Task<HttpResponse> task) throws Exception { return processResponseAsync(response); } }).continueWithTask(new Continuation<byte[], Task<Void>>() { @Overrid public Task<Void> then(Task<byte[]> task) throws Exception { return writeToDiskAsync(task.getResult()); } }, DISK_EXECUTOR);
  16. dependencies { // Facebook Dependencies compile 'com.android.support:support-v4:25.0.0' compile 'com.android.support:appcompat-v7:25.0.0' compile

    'com.android.support:cardview-v7:25.0.0' compile 'com.android.support:customtabs:25.0.0' compile 'com.parse.bolts:bolts-android:1.4.0' … } Вони вже у вашому проекті...
  17. Отже, Promise 1. упорядковують асинхронні задачі 2. спрощують відловлювання помилок

    3. унифікують все до одного стандарту 4. просто круті і круто виглядають
  18. Отже, Promise 1. упорядковують асинхронні задачі 2. спрощують відловлювання помилок

    3. унифікують все до одного стандарту 4. просто круті і круто виглядають
  19. DIY: async/await на iOS let asyncQueue = DispatchQueue(label: "asyncQueue", attributes:

    .concurrent) let awaitQueue = DispatchQueue(label: "awaitQueue", attributes: .concurrent)
  20. DIY: async/await на iOS func async(_ body: @escaping () throws

    -> Void) { promise(execute: body).catch { _ in } }
  21. DIY: async/await на iOS func await<Result>(_ body: @escaping () throws

    -> T) throws -> T { guard label != DispatchQueue.main.label else { throw Error.lockedCurrentThread } var result: Result? var error: Error? let semaphore = DispatchSemaphore(value: 0) promise(execute: body).then(on: self) { val -> Void in result = val semaphore.signal() }.catch(on: self) { err in error = err semaphore.signal() } _ = semaphore.wait(timeout: DispatchTime(uptimeNanoseconds: UINT64_MAX)) guard let result = result else { throw Error.badResult } return result }
  22. DIY: async/await на iOS func setupNewUser(name: String) -> Promise<User> {

    return async { let newUser = try await(self.createUser(name)) //createUser returns Promise let friends = try await(self.getFacebookFriends(name)) newUser.addFriends(friends) return newUser } }
  23. fun loadStringAsync() = async<String> { val secondsToWait = 3 println("Started!")

    println("Waiting $secondsToWait seconds...") for (n in 0 until secondsToWait) { waitAsync(1.seconds).await() println("One second elapsed!") } println("Downloading url...") val result = MyNetTasks.downloadGoogleAsStringAsync().await() println("Downloaded") result } Kotlin async/await
  24. public class Store { public CompletableFuture<Boolean> buyItem(String itemTypeId, int cost)

    { if(!await(bank.decrement(cost))) { return completedFuture(false); } try { await(inventory.giveItem(itemTypeId)); return completedFuture(true); } catch (Exception ex) { await(bank.refund(cost)); throw new AppException(ex); } } } EA async/await для Java
  25. Android lifecycle + Promise 1. Не писати код в activity/fragment

    2. Але можна писати в retained instance 3. Можна юзати в сервісах, лоадерах 4. Якщо є архітектура (MVC, MVP, MVVM, MV*), то можна щось придумати
  26. QA