美文网首页
[iOS][OC] 自定义 Promise 处理串行的异步操作

[iOS][OC] 自定义 Promise 处理串行的异步操作

作者: BudSwift | 来源:发表于2018-11-08 08:31 被阅读27次

背景

iOS 应用中很多操作是异步的,比如:

  • 网络请求的回调
  • UIAlertController 等待用户点击事件的回调
  • 定位的回调

等等,当这些操作需要逐个串行去执行时,由于不同条件下的回调结果以及不同操作的回调顺序,如果连续嵌套会导致业务严重耦合,多个操作回调加上可能的错误处理就会形成常说的“回调地狱”(举例如下面的伪代码),造成逻辑可读性差,且影响以后的维护。

/// 回调地狱
- (void)callbackHell {
    [TestManager doSomethingWithCompletion:^{
        NSLog(@"No 1 done");
        [TestManager doSomethingWithCompletion:^{
            NSLog(@"No 2 done");
            [TestManager doSomethingWithCompletion:^{
                NSLog(@"No 3 done");
            }];
        }];
    }];
}

针对串行情况下的异步回调的处理,可以将异步回调进行一次封装处理,这种对一个操作执行的预期,通常称为 Promise

将每一个异步的回调进行封装后放入到 PromiseManager 处理,效果举例如下:

/// 使用 Promise
- (void)testPromise {
    GSPromise *a = [GSPromise promiseWithHandler:^(dispatch_block_t then){
        [TestManager doSomethingWithCompletion:^{
            NSLog(@"done a"); then();
        }];
    }];
    
    GSPromise *b = [GSPromise promiseWithHandler:^(dispatch_block_t then){
        [TestManager doSomethingWithCompletion:^{
            NSLog(@"done b"); then();
        }];
    }];
    
    GSPromise *c = [GSPromise promiseWithHandler:^(dispatch_block_t then){
        [TestManager doSomethingWithCompletion:^{
            NSLog(@"done c"); then();
        }];
    }];
    
    GSPromiseManager *manager = [GSPromiseManager manangerWithPromises:@[a, b]];
    [manager addPromise:c];
}

解决方案

串行操作的顺序是,一个操作结束后执行下一个操作,因此可将“执行下一个操作”这一事件,封装入一个 block 中 (称为 then),并要求上一个操作执行完成后调用。

此外,将操作需要执行的方法也封装入一个 block 中 (称为 handler),要求每一个操作都具备 handler 这一属性,因此将该属性声明为协议 GSPromisable(如下),要求操作去遵循。

/**
 what a promise will execute

 @param then should call this block after promise done
 */
typedef void(^GSPromiseHandler)(dispatch_block_t then);

@protocol GSPromisable <NSObject>
/**
 the handler which a promise should retain
 */
@property (nonatomic, copy) GSPromiseHandler handler;

@end

其中,遵循 GSPromisable 协议的对象即 promise, 都添加到 PromiseManager 所管理的容器数组中,每个 promise 的handler 属性,将由外部的 PromiseManager 在合适的时机调用。为实现 PromiseManager 对串行的管理,manager 在执行执行操作的 handler 时将上文的 then 操作传递到 handler 中,如此 handler 在完成自身操作后调用 then,实现下一步操作的继续,实现如下:

/// try to handle next operation
- (void)try2Start {
    if (self.isWorking) return;
    
    id <GSPromisable> first = container.firstObject;
    if (!first) return;
    
    self.working = YES;
    dispatch_block_t then = ^{
        self.working = NO;
        
        @synchronized (self) {
            if (!container.firstObject) return;
            [container removeObjectAtIndex:0];
        }
        
        [self try2Start];
    };
    
    first.handler(then);
}

值得一提的是,这种设计思路类似于前文的《[iOS] [OC] 关于block回调、高阶函数“回调再调用”及项目实践》

源码及demo

GSPromise@GitHub

延伸

关于异步的操作处理有许多优秀的开源框架可以学习,推荐:

感谢同事 Zoe ,其对工作水平的不懈追求,促使更好方案的实现和改进。

加我微信沟通。


相关文章

  • [iOS][OC] 看 BRYSerialAnimationQu

    背景 上文 《自定义 Promise 处理串行的异步操作》 分析了串行的异步操作的自定义 Promise 处理。P...

  • [iOS][OC] 自定义 Promise 处理串行的异步操作

    背景 iOS 应用中很多操作是异步的,比如: 网络请求的回调 UIAlertController 等待用户点击事件...

  • ES6的学习(下)

    promise:异步操作同步化 同步 -- 串行 简单、方便异步 -- 并行 性能高、体验好promise的是...

  • ES6 Primise异步编程

    异步操作流程化的手段 #Promise处理异步操作 Promise,使异步操作变得流程化的手段之一,例如“异步A ...

  • 小程序 Promise

    Promise 表示一个异步操作对象,它让我们可以在外部处理异步操作完成或者失败的结果。Promise 是 ES6...

  • promise学习

    1. 什么是promise promise抽象异步处理对象以及对其进行各种操作的组件.js中处理异步一般都是通过回...

  • Promise并发处理(react)

    有时候需要处理一些批量操作,这样就有可能用到并发操作。先看Promise:处理异步并发的可以是Promise.al...

  • Promise分析总结(分析中...)

    什么是Promise Promise是抽象异步处理对象以及对其进行各种操作的组件 Promise简介 目前大致有下...

  • Node 学习(二)

    Promise学习 Promise含义 容器,保存异步操作的结果对象,获取异步操作的消息 Promise对象特点 ...

  • 《JS原理、方法与实践》- ES6新增对象(下篇)

    异步处理(Promise) ES2015中新增的Promise对象专门用于处理异步。Promise对象使用then...

网友评论

      本文标题:[iOS][OC] 自定义 Promise 处理串行的异步操作

      本文链接:https://www.haomeiwen.com/subject/fbjixqtx.html