精简的异步Promise实现

作者: 马修王 | 来源:发表于2018-11-02 13:11 被阅读23次

    Promise在web前端的开发工程师中使用的非常频繁,通过then使同步的编程思路来进行异步调用,使得异步编码变得非常的简单。iOS也有PromiseKit这样的开源库可以使用,不过自己实现一个使用起来会更方便和贴近。


    web端的Promise使用

    //第一个异步任务
        function run_a(){
            return new Promise(function(resolve, reject){
                //假设已经进行了异步操作,并且获得了数据
                resolve("step1");
            });
        }
        //第二个异步任务
        function run_b(data_a){
            return new Promise(function(resolve, reject){
                //假设已经进行了异步操作,并且获得了数据
                console.log(data_a);
                resolve("step2");
            });
        }
        //第三个异步任务
        function run_c(data_b){
            return new Promise(function(resolve, reject){
                //假设已经进行了异步操作,并且获得了数据
                console.log(data_b);
                resolve("step3");
            });
        }
    
        //连续调用
        run_a().then(function(data){
            return run_b(data);
        }).then(function(data){
            return run_c(data);
        }).then(function(data){
            console.log(data);
        });
    
        /*运行结果
          step1
          step2
          step3
        */
    

    参考上面的例子,对Promise稍微有些了解的应该都知道Promise包装了一个异步调用并生成一个Promise实例,当异步调用返回的时候根据调用的结果分别调用实例化时传入的resolvereject方法,这个时候then就会接收到对应的数据,这个是Promise最基本使用,当然真正的Promise还包含了很多其它的使用,这里我就使用OC实现最基本的异步调用then功能。

    Objective C 的实现

    实现代码放在github上,只有一个类文件可以随意的copy到工程中:https://github.com/MathewWang/WWPromise

    如何使用

    // Resolve Example
      WWPromise.promise(^(ResolveFunc resolve, RejectFunc reject){
          dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
              resolve(@"aaa");
          });
      }).then(^(NSString *result){
          NSLog(@"###promise the result is 111: %@", result);
    
          return WWPromise.promise(^(ResolveFunc resolve, RejectFunc reject){
              dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                  resolve([result stringByAppendingString:@"bbb"]);
              });
          });
      }, nil).then(^(NSString *result){
          NSLog(@"###promise the result is 222: %@", result);
    
          return [WWPromise empty];
      }, nil);
      
    // Reject Example
       WWPromise.promise(^(ResolveFunc resolve, RejectFunc reject){
          dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
              reject(@"aaa");
          });
      }).then(nil, ^(NSString *result){
          NSLog(@"###promise the result is 111: %@", result);
    
          return [WWPromise empty];
      });
      
    

    参照上面的例子,在添加then的时候,对于resolvereject的回调函数,如果不需要直接传入nil即可,不需要返回参数的then需要返回一个[WWPromise empty]

    One More

    因为Promise在实例化的时候就开始执行异步调用了,这点和RAC的冷信号不一样(冷信号是订阅时触发异步调用的),因此我们可以将Promise再进行一次封装使得对于OC的开发更加友好,这也是我们业务中真正使用的样子:
    实现一个抽象类“AbstractPromiseExecution”

    typedef void(^ExecutionSuccess)(id result);
    typedef void(^ExecutionFailed)(NSError *error);
    
    @interface AbstractPromiseExecution()
    
    @property (nonatomic, strong) ExecutionSuccess success;
    @property (nonatomic, strong) ExecutionFailed failed;
    
    
    @end
    
    @implementation AbstractPromiseExecution
    
    - (WWPromise *(^)(id))promise{
        return ^(id bizDatas){
            return WWPromise.promise(^(ResolveFunc resolve, RejectFunc reject){
                //设置success
                self.success = ^(id result) {
                    resolve(result);
                };
                //设置failed
                self.failed = ^(NSError *error) {
                    reject(error);
                };
                [self startExecute:bizDatas];
            });
        };
    }
    
    - (void)startExecute:(id) bizDatas{
        //override by subclass
    }
    

    从上面的抽象类很明显的看出来,- promise方法会返回一个Promise实例,将业务的successfailed回调赋值,同时会执行模板方法- (void)startExecute:(id) bizDatas将需要传递的业务数据bizDatas传递下去,因此业务类只要继承AbstractPromiseExecution然后复写- (void)startExecute:(id) bizDatas方法,在其中添加自己的业务逻辑,成功后调用 success 或者 failed,事例代码如下:

    //子类 1
    @interface FetchUserGroupInfoExecution : AbstractPromiseExecution
    
    @end
    
    @implementation FetchUserGroupInfoExecution
    
    - (void)startExecute:(id) bizDatas{
         //做异步请求
        [UserService requestUserGroup:^(id result){
              strongSelf.success(result);
        } error:^(NSError *errorInfo){
              strongSelf.failed(errorInfo);
        }];
    }
    
    @end
    
    //子类 2
    @interface CheckGroupAuthrizationExecution : AbstractPromiseExecution
    
    @end
    
    @implementation CheckGroupAuthrizationExecution
    
    - (void)startExecute:(id) bizDatas{
         //做异步请求
        [UserGroupService checkGroupAuthrization:^(id result){
              strongSelf.success(result);
        } error:^(NSError *errorInfo){
              strongSelf.failed(errorInfo);
        }];
    }
    
    @end
    
    

    这两个子类是先获取用户的组信息,然后在获取这个组的权限信息,在业务使用时候如下:

    FetchUserGroupInfoExecution *fetchExecution = [FetchUserGroupInfoExecution new];
    
    CheckGroupAuthrizationExecution *checkExecution = [CheckGroupAuthrizationExecution new];
    
    fetchExecution.promise(@{@"userId":@123})
    .then(^(id res){
      //Do business
      return checkExecution.promise(res);
    },^(NSError *error){
      //Do error handling
    }
    ).then(^(id res){
      //Do business
      return [WWPromise empty];
    },^(NSError *error){
      //Do error handling
    }
    );
    
    

    通过上面这样的简单封装,以后的业务扩展也是非常的容易,编写也很简单,子类只要关心传进来的数据做与自己相关的业务处理即可。

    相关文章

      网友评论

        本文标题:精简的异步Promise实现

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