精简的异步Promise实现

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实现)