美文网首页
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