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). Розглянемо основну теорію, подивимось, куди і як то все рухається.

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