美文网首页
Promises 源码学习记录

Promises 源码学习记录

作者: whlpkk | 来源:发表于2021-06-08 21:05 被阅读0次

一、前言

最近学习了 Google 的 promises 库,这里记录一下。库的 GitHub 地址: https://github.com/google/promises,方便大家直接阅读源码,提高水平。

为什么引入Promise?

在日常开发中,异步操作是很常见的情况,比如发起网络请求后,处理网络请求的结果一般都是异步操作,我们一般通过block或者delegate来执行异步操作。但是当有多个异步操作需要嵌套执行时,写出的代码结构就会比较混乱,难以阅读,比较容易出bug。
假设有这样的一种场景,播放加密视频时,需要先通过资源ID获取到视频ID,然后进行解密操作,最后拿解密后的结果去请求视频的播放地址或者视频本身,一般写法,代码如下:

// 仅供演示,未考虑引用循环以及错误处理
[self getVideoIDWithAssetResourceID:@"resource-id" complection:^(NSString *videoID) {
    [self decryptVideoWithVideoID:videoID complection:^(NSString *decryptResult) {
        [self requestVideoDataWithParam:decryptResult complection:^(NSString *videoPlayURLString) {
            [self.player setVideoURLString:videoPlayURLString];
        }];
    }];
}];

使用promises库,可以将代码变为如下写法:

[[[[[FBLPromise do:^id {
    return [FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
        [self getVideoIDWithAssetResourceID:@"resource-id" complection:^(NSString *videoID) {
            fulfill(videoID);
        }];
    }];
}] then:^id(NSString *value){
    return [FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
        [self decryptVideoWithVideoID:value complection:^(NSString *decryptResult) {
            fulfill(decryptResult);
        }];
    }];
}] then:^id(NSString *value){
    return [FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
        [self requestVideoDataWithParam:value complection:^(NSString *videoPlayURLString) {
            fulfill(videoPlayURLString);
        }];
    }];
}] then:^id(NSString *value) {
    [self.player setVideoURLString:value];
    return value;
}] catch:^(NSError *error) {
    NSLog(@"play failed!");
}];

//还可以使用链式调用
FBLPromise.doOn(dispatch_get_main_queue(), ^id {
    return [FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
        [self getVideoIDWithAssetResourceID:@"resource-id" complection:^(NSString *videoID) {
            fulfill(videoID);
        }];
    }];
}).then(^id(NSString *value){
    return [FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
        [self decryptVideoWithVideoID:value complection:^(NSString *decryptResult) {
            fulfill(decryptResult);
        }];
    }];
}).then(^id(NSString *value){
    return [FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
        [self requestVideoDataWithParam:value complection:^(NSString *videoPlayURLString) {
            fulfill(videoPlayURLString);
        }];
    }];
}).then(^id(NSString *value) {
    [self.player setVideoURLString:value];
    return value;
}).catch(^(NSError *error) {
    NSLog(@"play failed!");
});

如果将相应逻辑转变为同步,则可进一步简化为如下写法:

dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
FBLPromise.doOn(queue, ^id {
    return [self getVideoIDWithAssetResourceID:@"resource-id"];
}).thenOn(queue, ^id(NSString *value){
    return [self decryptVideoWithVideoID:value];
}).thenOn(queue, ^id(NSString *value){
    return [self requestVideoDataWithParam:value];
}).thenOn(dispatch_get_main_queue(), ^id(NSString *value) {
    [self.player setVideoURLString:value];
    return value;
}).catch(^(NSError *error) {
    NSLog(@"play failed!");
});

二、Promise 的简介

  • 概念

Promise 把每一个异步操作都封装成一个Promise对象,这个Promise对象存储这个异步操作执行完毕的 future 结果。本质上是异步函数(promise)的返回值(future),通过这种方式,就能提前获取到结果,并处理下一步骤。

  • 状态迁移

Promise对象的状态:

  1. pending:任务执行态,状态可能进入下面的 fulfilled 或 rejected 状态。
  2. fulfilled:任务完成态,promise不能转为任何其他状态,必须有一个值,且此值不能改变。
  3. rejected:任务拒绝态,promise不能转为任何其他状态,必须有一个原因(reason),且此原因不能改变。

三、Promises 源码分析

先看FBLPromise.h,它提供了暴露给业务方的接口。上文提到了promise的状态,promise.h提供了初始化三种状态的promise实例函数以及由pending转为fulfilled或者rejected状态的函数,同时支持指定回调的派发队列的能力。

/**
 Default dispatch queue used for `FBLPromise`, which is `main` if a queue is not specified.
 */
@property(class) dispatch_queue_t defaultDispatchQueue NS_REFINED_FOR_SWIFT;

/**
 Creates a pending promise.
 */
+ (instancetype)pendingPromise NS_REFINED_FOR_SWIFT;

/**
 Creates a resolved promise.

 @param resolution An object to resolve the promise with: either a value or an error.
 @return A new resolved promise.
 */
+ (instancetype)resolvedWith:(nullable id)resolution NS_REFINED_FOR_SWIFT;

/**
 Synchronously fulfills the promise with a value.

 @param value An arbitrary value to fulfill the promise with, including `nil`.
 */
- (void)fulfill:(nullable Value)value NS_REFINED_FOR_SWIFT;

/**
 Synchronously rejects the promise with an error.

 @param error An error to reject the promise with.
 */
- (void)reject:(NSError *)error NS_REFINED_FOR_SWIFT;

再看FBLPromisePrivate.h,提供库内部使用的接口和定义,它提供了一些回调block的定义、对promise状态监听的响应函数以及用于支持链式调用的函数。

typedef void (^FBLPromiseOnFulfillBlock)(Value __nullable value) NS_SWIFT_UNAVAILABLE("");
typedef void (^FBLPromiseOnRejectBlock)(NSError *error) NS_SWIFT_UNAVAILABLE("");
typedef id __nullable (^__nullable FBLPromiseChainedFulfillBlock)(Value __nullable value)
    NS_SWIFT_UNAVAILABLE("");
typedef id __nullable (^__nullable FBLPromiseChainedRejectBlock)(NSError *error)
    NS_SWIFT_UNAVAILABLE("");

/**
 Creates a pending promise.
 */
- (instancetype)initPending NS_SWIFT_UNAVAILABLE("");

/**
 Creates a resolved promise.

 @param resolution An object to resolve the promise with: either a value or an error.
 @return A new resolved promise.
 */
- (instancetype)initWithResolution:(nullable id)resolution NS_SWIFT_UNAVAILABLE("");

/**
 Invokes `fulfill` and `reject` blocks on `queue` when the receiver gets either fulfilled or
 rejected respectively.
 */
- (void)observeOnQueue:(dispatch_queue_t)queue
               fulfill:(FBLPromiseOnFulfillBlock)onFulfill
                reject:(FBLPromiseOnRejectBlock)onReject NS_SWIFT_UNAVAILABLE("");

/**
 Returns a new promise which gets resolved with the return value of `chainedFulfill` or
 `chainedReject` blocks respectively. The blocks are invoked when the receiver gets either
 fulfilled or rejected. If `nil` is passed to either block arg, the returned promise is resolved
 with the same resolution as the receiver.
 */
- (FBLPromise *)chainOnQueue:(dispatch_queue_t)queue
              chainedFulfill:(FBLPromiseChainedFulfillBlock)chainedFulfill
               chainedReject:(FBLPromiseChainedRejectBlock)chainedReject NS_SWIFT_UNAVAILABLE("");

接下来看看最重要同时也是精华所在的then方法:

- (instancetype)initPending {
  self = [super init];
  if (self) {
    dispatch_group_enter(FBLPromise.dispatchGroup);
  }
  return self;
}

- (FBLPromise *)then:(FBLPromiseThenWorkBlock)work {
  return [self onQueue:FBLPromise.defaultDispatchQueue then:work];          //(1)
}

- (FBLPromise *)onQueue:(dispatch_queue_t)queue then:(FBLPromiseThenWorkBlock)work {
  NSParameterAssert(queue);
  NSParameterAssert(work);
  return [self chainOnQueue:queue chainedFulfill:work chainedReject:nil];   //(2)
}

- (FBLPromise *)chainOnQueue:(dispatch_queue_t)queue
              chainedFulfill:(FBLPromiseChainedFulfillBlock)chainedFulfill
               chainedReject:(FBLPromiseChainedRejectBlock)chainedReject {
  NSParameterAssert(queue);
    // 创建一个新的promise对象,用来链式调用或返回结果
  FBLPromise *promise = [[FBLPromise alloc] initPending];                   //(3)
  // 当 self 被 fulfilled 或者 rejected 时,resolver都会调用,所以这里抽离block,避免重复代码;
  __auto_type resolver = ^(id __nullable value) {
    if ([value isKindOfClass:[FBLPromise class]]) {                        // (9)
      //这里的value是thenBlock返回的,如果返回的是一个promise,则 returnPromise 会添加订阅,当returnPromise 结束,调用新创建的promise的结束方法,如果此时newPromise也有订阅者(被then过),触发newPromise的thenBlock。   
      [(FBLPromise *)value observeOnQueue:queue
          fulfill:^(id __nullable value) {
            [promise fulfill:value];
          }
          reject:^(NSError *error) {
            [promise reject:error];
          }];
    } else {
      [promise fulfill:value];
    }
  };
                 
  // 添加订阅,当self被fulfilled,即会触发下面的fulfill回调block,如果 thenBlock(chainedFulfill)存在,则先执行 thenBlock,然后thenBlock重新生成一个value值(value值也可能不会变化,主要还得看thenBlock函数里有没有改变value);接下来把这个重新赋值的value扔给resolverBlock,resolverBlock会把这个新的value给newPromise,newPromise会调用fulfilled方法,如果此时newPromise也有订阅者(被then过),则就会把这个新value传递给下一个newNewPromise ...
  [self observeOnQueue:queue
      fulfill:^(id __nullable value) {
        value = chainedFulfill ? chainedFulfill(value) : value;             // (8)
        resolver(value);
      }
      reject:^(NSError *error) {
        id value = chainedReject ? chainedReject(error) : error;            // (8)
        resolver(value);
      }];
  return promise;
}

// 添加订阅block,当前promise结束时,回调对应的block(onFulfill/onReject)
- (void)observeOnQueue:(dispatch_queue_t)queue
               fulfill:(FBLPromiseOnFulfillBlock)onFulfill
                reject:(FBLPromiseOnRejectBlock)onReject {
  NSParameterAssert(queue);
  NSParameterAssert(onFulfill);
  NSParameterAssert(onReject);
  // 如果添加订阅的时候promise已经结束了,则直接把结果返回给订阅者,即调用onFulfill或onReject。
  @synchronized(self) {                                                   // (4)
    switch (_state) {
      // 默认的state,即待处理的事件
      case FBLPromiseStatePending: {
        // 如果promise对象还没有观察者数组,new一个,因为一个Promise可以被then很多次,即添加多个订阅
        if (!_observers) {
          _observers = [[NSMutableArray alloc] init];
        }
        [_observers addObject:^(FBLPromiseState state, id __nullable resolution) {
          dispatch_group_async(FBLPromise.dispatchGroup, queue, ^{
            switch (state) {                                             // (7)
              case FBLPromiseStatePending:
                break;
              case FBLPromiseStateFulfilled:
                onFulfill(resolution);   
                break;
              case FBLPromiseStateRejected:
                onReject(resolution);
                break;
            }
          });
        }];                                                               // (5)
        break;
      }
      // 当前promise已经结束
      case FBLPromiseStateFulfilled: {
        dispatch_group_async(FBLPromise.dispatchGroup, queue, ^{
          onFulfill(self->_value); 
        });
        break;
      }
      case FBLPromiseStateRejected: {
        dispatch_group_async(FBLPromise.dispatchGroup, queue, ^{
          onReject(self->_error);
        });
        break;
      }
    }
  }
}

// 当完成时,回调所有订阅者
- (void)fulfill:(nullable id)value {
  if ([value isKindOfClass:[NSError class]]) {
    [self reject:(NSError *)value];
  } else {
    @synchronized(self) {
      if (_state == FBLPromiseStatePending) {                              
        _state = FBLPromiseStateFulfilled;
        _value = value;
        _pendingObjects = nil;
        for (FBLPromiseObserver observer in _observers) {
          observer(_state, _value);                                     // (6)
        }
        _observers = nil;
        dispatch_group_leave(FBLPromise.dispatchGroup);
      }
    }
  }
}

// 当完成时,回调所有订阅者
- (void)reject:(NSError *)error {
  NSAssert([error isKindOfClass:[NSError class]], @"Invalid error type.");

  if (![error isKindOfClass:[NSError class]]) {
    // Give up on invalid error type in Release mode.
    @throw error;  // NOLINT
  }
  @synchronized(self) {
    if (_state == FBLPromiseStatePending) {
      _state = FBLPromiseStateRejected;
      _error = error;
      _pendingObjects = nil;
      for (FBLPromiseObserver observer in _observers) {
        observer(_state, _error);                                       // (6)
      }
      _observers = nil;
      dispatch_group_leave(FBLPromise.dispatchGroup);
    }
  }
}


主要的执行步骤已经在上面做了标注。

四、其他能力

  • then
typedef id __nullable (^FBLPromiseThenWorkBlock)(Value __nullable value) NS_SWIFT_UNAVAILABLE("");
- (FBLPromise *)then:(FBLPromiseThenWorkBlock)work NS_SWIFT_UNAVAILABLE("");
- (FBLPromise *)onQueue:(dispatch_queue_t)queue
                   then:(FBLPromiseThenWorkBlock)work NS_REFINED_FOR_SWIFT;

then可以看做简版的chainOnQueue: chainedFulfill: chainedReject:,then对应的是chainedFulfill:。如果前面被监听的promise 状态state是fulfilled,才会调用then对应的的FBLPromiseThenWorkBlock,即promise通过决议时才被调用。如果是rejected,则不会走then对应的block。then可以理解成用于捕获前面异步任务的成功fulfilled value

  • catch
typedef void (^FBLPromiseCatchWorkBlock)(NSError *error) NS_SWIFT_UNAVAILABLE("");
- (FBLPromise *)catch:(FBLPromiseCatchWorkBlock)reject NS_SWIFT_UNAVAILABLE("");
- (FBLPromise *)onQueue:(dispatch_queue_t)queue
                  catch:(FBLPromiseCatchWorkBlock)reject NS_REFINED_FOR_SWIFT;

catch和then类似,只不过是监听的promise的状态state是rejected时才会调用。

  • always
- (FBLPromise *)always:(FBLPromiseAlwaysWorkBlock)work NS_SWIFT_UNAVAILABLE("");
- (FBLPromise *)onQueue:(dispatch_queue_t)queue
                 always:(FBLPromiseAlwaysWorkBlock)work NS_REFINED_FOR_SWIFT;

和catch、then类似,无论监听的promise的状态变为fulfilled还是rejected,always block都会执行

  • async
typedef void (^FBLPromiseFulfillBlock)(Value __nullable value) NS_SWIFT_UNAVAILABLE("");
typedef void (^FBLPromiseRejectBlock)(NSError *error) NS_SWIFT_UNAVAILABLE("");
typedef void (^FBLPromiseAsyncWorkBlock)(FBLPromiseFulfillBlock fulfill,
                                         FBLPromiseRejectBlock reject) NS_SWIFT_UNAVAILABLE("");
+ (instancetype)async:(FBLPromiseAsyncWorkBlock)work NS_SWIFT_UNAVAILABLE("");
+ (instancetype)onQueue:(dispatch_queue_t)queue
                  async:(FBLPromiseAsyncWorkBlock)work NS_REFINED_FOR_SWIFT;

创建一个pending的promise,并且异步执行work block,work block 执行完成后调用 fulfill(value)

  • do
typedef id __nullable (^FBLPromiseDoWorkBlock)(void) NS_SWIFT_UNAVAILABLE("");
+ (instancetype)do:(FBLPromiseDoWorkBlock)work NS_SWIFT_UNAVAILABLE("");
+ (instancetype)onQueue:(dispatch_queue_t)queue do:(FBLPromiseDoWorkBlock)work NS_REFINED_FOR_SWIFT;

同async类似,只不过通过直接调用work block来获取value,即work block 需要同步返回 value

  • any
+ (FBLPromise<NSArray *> *)any:(NSArray *)promises NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise<NSArray *> *)onQueue:(dispatch_queue_t)queue
                               any:(NSArray *)promises NS_REFINED_FOR_SWIFT;

传入一个promise数组,Any会等待所有的promise 状态变为fulfilled或者rejected,只要有一个prmise状态完成,则结果promise状态会被决议成fulfilled,当所有的promise状态都变为rejected时,结果promise状态也变为rejected,error信息同状态最后变为rejected的promise的error相同。

  • all
+ (FBLPromise<NSArray *> *)all:(NSArray *)promises NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise<NSArray *> *)onQueue:(dispatch_queue_t)queue
                               all:(NSArray *)promises NS_REFINED_FOR_SWIFT;

传入一个promise数组,All会等待所有的promise 状态变为fulfilled,然后按传入promise数组的顺序返回一个value的数组。如果任何一个promise被rejected,则结果promise立刻被rejected。和any类似

  • race
+ (instancetype)race:(NSArray *)promises NS_SWIFT_UNAVAILABLE("");
+ (instancetype)onQueue:(dispatch_queue_t)queue race:(NSArray *)promises NS_REFINED_FOR_SWIFT;

传入一个promise数组,等待第一个结束的promise,结果promise 和 第一个结束的promise 结果相同。

  • await
FOUNDATION_EXTERN id __nullable FBLPromiseAwait(FBLPromise *promise,
                                                NSError **error) NS_REFINED_FOR_SWIFT;

等待promise结束,成功返回结果,失败返回nil,从error字段获取错误信息,会阻塞当前线程

  • delay
- (FBLPromise *)delay:(NSTimeInterval)interval NS_SWIFT_UNAVAILABLE("");
- (FBLPromise *)onQueue:(dispatch_queue_t)queue
                  delay:(NSTimeInterval)interval NS_REFINED_FOR_SWIFT;

创建一个pending的new promise,当self状态变为fulfilled,在delay的时间后,new promise状态变为fulfilled,value同self相同,如果self变为rejected,则忽略delay,直接rejected

  • recover
typedef id __nullable (^FBLPromiseRecoverWorkBlock)(NSError *error) NS_SWIFT_UNAVAILABLE("");
- (FBLPromise *)recover:(FBLPromiseRecoverWorkBlock)recovery NS_SWIFT_UNAVAILABLE("");
- (FBLPromise *)onQueue:(dispatch_queue_t)queue
                recover:(FBLPromiseRecoverWorkBlock)recovery NS_REFINED_FOR_SWIFT;

当receiver变为rejected时,返回一个新的promise,代替rejected的promise

  • retry
typedef id __nullable (^FBLPromiseRetryWorkBlock)(void) NS_SWIFT_UNAVAILABLE("");
typedef BOOL (^FBLPromiseRetryPredicateBlock)(NSInteger, NSError *) NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise *)retry:(FBLPromiseRetryWorkBlock)work NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise *)onQueue:(dispatch_queue_t)queue
                  retry:(FBLPromiseRetryWorkBlock)work NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise *)attempts:(NSInteger)count
                   retry:(FBLPromiseRetryWorkBlock)work NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise *)onQueue:(dispatch_queue_t)queue
               attempts:(NSInteger)count
                  retry:(FBLPromiseRetryWorkBlock)work NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise *)attempts:(NSInteger)count
                   delay:(NSTimeInterval)interval
               condition:(nullable FBLPromiseRetryPredicateBlock)predicate
                   retry:(FBLPromiseRetryWorkBlock)work NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise *)onQueue:(dispatch_queue_t)queue
               attempts:(NSInteger)count
                  delay:(NSTimeInterval)interval
              condition:(nullable FBLPromiseRetryPredicateBlock)predicate
                  retry:(FBLPromiseRetryWorkBlock)work NS_REFINED_FOR_SWIFT;
  • 创建一个pending的promise,根据work的返回值,变更状态变为fulfilled,如果将要变更rejected,则retry,在所有的retry次数完成后变为rejected。默认retry count 1,interval 1s

  • timeout
- (FBLPromise *)timeout:(NSTimeInterval)interval NS_SWIFT_UNAVAILABLE("");
- (FBLPromise *)onQueue:(dispatch_queue_t)queue
                timeout:(NSTimeInterval)interval NS_REFINED_FOR_SWIFT;

返回一个pending promise,等待self结果直到timeout。它或者以self相同的resolution变为fulfilled或者以超时类型的error变为rejected

  • reduce
typedef id __nullable (^FBLPromiseReducerBlock)(Value __nullable partial, id next)
    NS_SWIFT_UNAVAILABLE("");
- (FBLPromise *)reduce:(NSArray *)items
               combine:(FBLPromiseReducerBlock)reducer NS_SWIFT_UNAVAILABLE("");
- (FBLPromise *)onQueue:(dispatch_queue_t)queue
                 reduce:(NSArray *)items
                combine:(FBLPromiseReducerBlock)reducer NS_SWIFT_UNAVAILABLE("");

基于当前的promise(self)和items数据源,实现reduce功能,当前promise的值为初值,最终返回的promise是数组最后一个Item转换的promise。伪代码FBLPromise *promise = self; promise = promise + item[index]

  • timeout
- (FBLPromise *)timeout:(NSTimeInterval)interval NS_SWIFT_UNAVAILABLE("");
- (FBLPromise *)onQueue:(dispatch_queue_t)queue
                timeout:(NSTimeInterval)interval NS_REFINED_FOR_SWIFT;

返回一个pending promise,等待self结果直到timeout。它或者以self相同的resolution变为fulfilled或者以超时类型的error变为rejected

  • validate
typedef BOOL (^FBLPromiseValidateWorkBlock)(Value __nullable value) NS_SWIFT_UNAVAILABLE("");
- (FBLPromise *)validate:(FBLPromiseValidateWorkBlock)predicate NS_SWIFT_UNAVAILABLE("");
- (FBLPromise *)onQueue:(dispatch_queue_t)queue
               validate:(FBLPromiseValidateWorkBlock)predicate NS_REFINED_FOR_SWIFT;

验证promise fulfilled后的value,如果不能通过验证,则reject此promise

相关文章

网友评论

      本文标题:Promises 源码学习记录

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